1. 程式人生 > 其它 >Java進階學習之網路程式設計(4)

Java進階學習之網路程式設計(4)

目錄
《計算機網路》作為計算機專業的必修課,估計大家對他仍有後怕,這本書很厚,知識面很廣,建議有時間的朋友通篇閱讀和理解。

1.網路程式設計概述

1.1.目的

通過通訊線路將多臺計算機連線起來,並進行資料傳輸。

1.2.常用的網路協議

1.2.1.TCP

TCP(Transmission Control Protocol):傳輸控制協議,是一種面向連線、可靠的、基於位元組流的傳輸層通訊協議。

TCP的三次握手
SYN:同步序列編號Synchronize Sequence Numbers
ACK:確認字元Acknowledge character

  1. 第一次握手:A的TCP客戶端首先建立傳輸控制塊TCB,然後向B傳送連線請求報文段(SYN=1,seq=x),A進入SYN-SENT狀態;
  2. 第二次握手:B收到連線請求報文後,如同意建立連線,則向A傳送確認(SYN=1,ACK=1,確認號ack=x+1,seq=y),B進入SYN-RCVD狀態;
  3. 第三次握手:A收到B的確認後,向B發出確認報文(ACK=1,確認號ack=y+1,seq=x+1),A進入ESTABLISHED,B收到A的確認後也進入ESTABLISHED。

TCP四次揮手
MSL:報文最大存活時間

  1. A向B傳送連線釋放報文段(FIN=1,seq=u),並停止再發送資料,主動關閉TCP連線,進入FIN-WAIT-1狀態,等待B的確認;
  2. B收到後發出確認報文段(ACK=1,ack=u+1,seq=v),B進入CLOSE-WAIT狀態,此時TCP連線處於半關閉狀態,A到B的連線釋放;
  3. A收到B的確認後,進入FIN-WAIT-2狀態,等待B發出連線釋放報文;
  4. B沒有向A發出資料,B發出連線釋放報文(FIN=1,ACK=1,seq=w,ack=u+1),B進入TIME-WAIT狀態,等待A確認;
  5. A收到B的連線釋放報文後,發出確認報文(ACK=1,seq=u+1,ack=w+1),A進入TIME-WAIT狀態,此時TCP未釋放掉,經過時間等待計數器設定的時間2MSL後,A進入CLOSED狀態。
1.2.2.UDP

UDP(User Datagram Protocol):使用者資料報協議,是一種無連線的傳輸協議。
特點:

  • 不可靠的協議,不建立連線,不進行資料檢查,不等待應答,導致可能會出現資料丟失等現象
  • 報頭很短,開銷很小
  • 有較好的實用性,傳輸效率很高,受軟體效能、頻寬、收發端主機效能限制

2.Socket網路程式設計

2.1.Socket是什麼

套接字Socket就是雙向通訊中一端的抽象。
Socket由IP地址和埠port確認。

2.2.Socket工作流程

  1. 伺服器開啟監聽
  2. 客戶端請求連線
  3. 確認連線

2.3.案例

服務端編寫:

public class MyServer extends Thread {

    private ServerSocket serverSocket;

    public MyServer(int port) throws IOException {
        serverSocket = new ServerSocket(8888);
        System.out.println("服務端已啟動,監聽埠:" + serverSocket.getLocalPort());
    }

    @Override
    public void run() {
        Socket server = null;
        OutputStream os = null;
        DataOutputStream dos = null;
        while (true) {
            try {
                server = serverSocket.accept();
                System.out.println(server.getRemoteSocketAddress() + "連線成功!");
                os = server.getOutputStream();
                dos = new DataOutputStream(os);
                dos.writeUTF("hello!");
                dos.flush();

                dos.close();
                os.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        try {
            Thread t = new MyServer(8888);
            t.run();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

客戶端編寫:

public class MyClient {
    public static void main(String[] args) {
        Socket client = null;
        InputStream is = null;
        DataInputStream dis = null;
        try {
            client = new Socket("127.0.0.1", 8888);
            is = client.getInputStream();
            dis = new DataInputStream(is);
            System.out.println(dis.readUTF());

            dis.close();
            is.close();
            client.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

然後按照Socket工作流程,先啟動服務點監聽,執行結果:

啟動客戶端進行連線,執行結果:

連線成功後,接收到服務端發來的字串"hello!"
看一下服務端有什麼變化:

由於服務端是個死迴圈對8888埠進行監聽,我們啟動客戶端多次看看服務端有什麼變化: