Java網路程式設計基礎學習與整理

WowVoid發表於2020-12-09

網路程式設計

1網路通訊的要素

1.1網路模型整理

TCP/IP參考模型

1.2 IP

  • ip定義:Internet Protocol,IP只為主機提供一種無連線、不可靠的、盡力而為的資料包傳輸服務,可以唯一地定位一臺網路計算機。(127.0.0.1為本機的localhost)
  • IP地址分類:
    • ipv4 : 由四個位元組組成,例如 127.0.0.1 網路號+主機號
    • ipv6 : 128位,8組,每組4個16進位制數,例如 2001:0db8:85a3:08d3:1319:8a2e:0370:7344,如果0000則省略
  • 公網(網際網路)-私網(區域網)
    • 192.168.xx.xx屬於區域網,專門給組織內部使用
    • ABCDE類地址根據網路號劃分,如圖所示,其中D類供組播使用,E類供科研使用
      ABCDE類劃分圖

1.3 埠

  • 埠表示計算機上一個程式的程式
  • 規定限制在2^16 0~65535之間
  • TCP UDP協議埠相隔離,但在單個協議下埠不能重複
  • 埠分類:
    • 公有埠:0~1023
      • HTTP:80
      • HTTPS:443
      • FTP:21
      • Telnet:23
    • 程式註冊埠:1024~49151,程式或者使用者使用
      • Tomcat:8080
      • MySQL:3306
      • Oracle:1521
      • Redis:6379
  • 動態埠、私有埠:49152~65535 不建議使用

1.4 通訊協議

  • TCP/UDP對比:

  • TCP:使用者傳輸協議(打電話)

    • 連線、穩定
    • 三次握手、四次揮手
    三次握手:
    	第一次握手:客戶端傳輸SYN=i給服務端,狀態置為SYN_SEND;
    	第二次握手:服務端接受SYN=i後,返回ACK=i+1且返回SYN=j,狀態置為SYN_RECV;
    	第三次握手:客戶端接受ACK後狀態置為ESTABLISHED,傳送ACK=j+1,服務端接受後狀態置為ESTABLISHED;
    四次揮手:
    	(1)客戶端傳送FIN,狀態置為FIN_WAIT1,接受ACK後改為FIN_WAIT2
    	(2)服務端接受FIN,返回ACK,狀態置為CLOSE_WAIT
    	(3)服務端資料傳輸完畢,返回FIN,狀態改為LAST_ACK,接受客戶端ACK後改為CLOSED
    	(4)客戶端接受FIN後狀態置為TIME_WAIT,2MS後置為CLOSED
    中間狀態:
    	CLOSED:初始狀態
    	LISTEN:監聽中
    	SYN_SENT:傳送SYN=i給服務端後
    	SYN_RCVD: 接受客戶端的SYN=i後
    	ESTABLISHED:已連線
    	FIN_WAIT_1:ESTABLISHED狀態下傳送FIN=i給客戶端後
    	FIN_WAIT_2:ESTABLISHED狀態下傳送FIN=i給客戶端後接收到ACK返回則為2
    	CLOSE_WAIT:FIN接受方,收到後返回ACK並置為CLOSE_WAIT,資料傳輸完畢後返回FIN且狀態改為LAST_ACK
    	TIME_WAIT:FIN發起方,收到對方返回的FIN後傳送ACK,置為TIME_WAIT,2MS後會改為CLOSED
    	LAST_ACK:CLOSE_WAIT資料傳輸完畢後返回FIN且狀態改為LAST_ACK
    	CLOSING:雙方同時發起FIN
    
  • UDP:使用者資料包協議(發簡訊)

    • 不連線、不穩定
    • 沒明確的客戶端服務端區分

    1.5 TCP通訊連線

  • 客戶端:
    1.建立Socket連線伺服器Socket
    2.傳送訊息

    public static void main(String[] args) {
        Socket socket = null;
        OutputStream outputStream = null;
        try {
            //獲取服務端地址和埠
            InetAddress serverIp = InetAddress.getByName("localhost");
            int port = 9999;
            //建立Socket連線
            socket = new Socket(serverIp, port);
            //輸出流輸出資訊
            outputStream = socket.getOutputStream();
            outputStream.write("hello".getBytes());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //關閉資源
        }
    }
    
  • 服務端
    1.建立ServerSocket
    2.等待客戶端連線
    3.接受資訊並處理

    public static void main(String[] args) {
        try {
            //等待Socket
            java.net.ServerSocket serverSocket = new java.net.ServerSocket(9999);
            while (true) {
                //等待客戶端連線
                Socket clientSocket = serverSocket.accept();
                //讀取
                InputStream inputStream = clientSocket.getInputStream();
                //管道流
                ByteArrayOutputStream bos = new ByteArrayOutputStream();
                byte[] buffer = new byte[1024];
                int len;
                while ((len = inputStream.read(buffer)) != -1) {
                    bos.write(buffer, 0, len);
                }
                System.out.println(bos.toString());
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //關閉資源
        }
    }
    

    1.5 TCP檔案傳輸

    客戶端:

    public static void main(String[] args) {
      try {
          InetAddress inetAddress = InetAddress.getByName("localhost");
          int port = 8888;
          Socket socket = new Socket(inetAddress, port);
          OutputStream outputStream = socket.getOutputStream();
          FileInputStream fileInputStream = new FileInputStream(new File("test.jpg"));
          int len;
          byte[] buffer = new byte[1024];
          while ((len = fileInputStream.read(buffer)) != -1) {
              outputStream.write(buffer,0,len);
          }
          //通知服務端輸出關閉
          socket.shutdownOutput();
          int len2;
          byte[] buffer2 = new byte[1024];
          //接受服務端返回資訊並列印
          InputStream inputStream = socket.getInputStream();
          ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
          while ((len2 = inputStream.read(buffer2)) != -1) {
              byteArrayOutputStream.write(buffer2, 0, len2);
          }
          System.out.println(byteArrayOutputStream.toString());
      } catch (Exception e) {
          e.printStackTrace();
      }finally {
          //關閉資源
      }
    }
    

    服務端:

        public static void main(String[] args) {
        try {
            ServerSocket serverSocket = new ServerSocket(8888);
            Socket accept = serverSocket.accept();
            InputStream inputStream = accept.getInputStream();
            FileOutputStream fileOutputStream = new FileOutputStream("new.jpg");
            int len;
            byte[] buffer = new byte[1024];
            while ((len = inputStream.read(buffer)) != -1) {
                fileOutputStream.write(buffer,0,len);
            }
            //給客戶端返回結束資訊
            OutputStream outputStream = accept.getOutputStream();
            outputStream.write("end transfer".getBytes());
            //結束後需要關閉套接字,否則會導致客戶端讀取中斷丟擲異常
            accept.close();
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            //關閉資源
        }
    }
    
未完待續

相關文章