網絡協議:計算機網絡可以使多台計算機實現連接,位於同一個網絡中的計算機在進行連接和通信時需要遵守一定的規則,這就好比在道路中行駛的汽車一定要遵守交通規則一樣。在計算機網絡中,這些連接和通信的規則被稱為網絡通信協議,它對數據的傳輸格式、傳輸速率、傳輸步驟等做了統一規定,通信雙方必須同時遵守才能完成數據交換。
TCP/IP協議中的四層分別是應用層、傳輸層、網絡層和鏈路層,每層分別負責不同的通信功能,接下來針對這四層進行詳細地講解。
鏈路層:用於定義物理傳輸通道,通常是對某些網絡連接設備的驅動協議,例如針對光纖、網線提供的驅動。
網絡層:網絡層是整個TCP/IP協議的核心,它主要用於將傳輸的數據進行分組,將分組數據發送到目標計算機或者網絡。
傳輸層:主要使網絡程序進行通信,在進行網絡通信時,可以采用TCP協議,也可以采用UDP協議。
應用層:主要負責應用程序的協議,例如HTTP協議、FTP協議等。
TCP/IP:
要想使網絡中的計算機能夠進行通信,必須為每台計算機指定一個標識號(IP地址),通過這個標識號來指定接受數據的計算機或者發送數據的計算機。通過IP地址可以連接到指定計算機,但如果想訪問目標計算機中的某個應用程序,還需要指定端口號。在計算機中,不同的應用程序是通過端口號區分的。端口號是用兩個字節(16位的二進制數)表示的,它的取值范圍是0~65535,其中,0~1023之間的端口號用於一些知名的網絡服務和應用,用戶的普通應用程序需要使用1024以上的端口號,從而避免端口號被另外一個應用或服務所占用。
從上圖中可以清楚地看到,位於網絡中一台計算機可以通過IP地址去訪問另一台計算機,並通過端口號訪問目標計算機中的某個應用程序。
UDP/TCP:
UDP是無連接通信協議,即在數據傳輸時,數據的發送端和接收端不建立邏輯連接。簡單來說,當一台計算機向另外一台計算機發送數據時,發送端不會確認接收端是否存在,就會發出數據,同樣接收端在收到數據時,也不會向發送端反饋是否收到數據。
由於使用UDP協議消耗資源小,通信效率高,所以通常都會用於音頻、視頻和普通數據的傳輸例如視頻會議都使用UDP協議,因為這種情況即使偶爾丟失一兩個數據包,也不會對接收結果產生太大影響。
但是在使用UDP協議傳送數據時,由於UDP的面向無連接性,不能保證數據的完整性,因此在傳輸重要數據時不建議使用UDP協議。
UDP協議:
send發送端:
//創建UDP協議
DatagramSocket ds = new DatagramSocket();
Scanner sc =new Scanner(System.in);
while(true) {
String s = sc.next();
//Stirng 字節數組
byte[] b = s.getBytes();
//Stirng 字節數組長度
int length = b.length;
//ip地址
InetAddress address = InetAddress.getByName("192.168.1.111");
//端口號
int port = 10086;
// 打包
DatagramPacket dp = new DatagramPacket(b, length, address, port);
//發送包數據
ds.send(dp);
//關閉資源
}
//ds.close();
receive接收端:
DatagramSocket ds = new DatagramSocket(10086);
while(true) {
byte[] bys = new byte[1024];
DatagramPacket dp = new DatagramPacket(bys, bys.length);
//System.out.println(InetAddress.getLocalHost());
ds.receive(dp);
//解析
System.out.println(new String(bys,0,dp.getLength()));
//ds.close();
}
TCP協議:
TCP通信同UDP通信一樣,都能實現兩台計算機之間的通信,通信的兩端都需要創建socket對象。區別在於,UDP中只有發送端和接收端,不區分客戶端與服務器端,計算機之間可以任意地發送數據。
而TCP通信是嚴格區分客戶端與服務器端的,在通信時,必須先由客戶端去連接服務器端才能實現通信,服務器端不可以主動連接客戶端,並且服務器端程序需要事先啟動,等待客戶端的連接。
在JDK中提供了兩個類用於實現TCP程序,一個是ServerSocket類,用於表示服務器端,一個是Socket類,用於表示客戶端。通信時,首先創建代表服務器端的ServerSocket對象,該對象相當於開啟一個服務,並等待客戶端的連接,然后創建代表客戶端的Socket對象向服務器端發出連接請求,服務器端響應請求,兩者建立連接開始通信。
send發送端:
//創建發送端Socket對象(創建連接)
Socket s = new Socket(InetAddress.getByName("192.168.1.111"), 10086);
//獲取輸出流對象
OutputStream os = s.getOutputStream();
String str = "hello";
os.write(str.getBytes());
//釋放資源
os.close();
s.close();
receive接收端:
//創建接收端Socket對象
ServerSocket ss = new ServerSocket(10086);
//監聽
Socket s = ss.accept();
//獲取輸入流對象
InputStream is = s.getInputStream();
//獲取數據
byte[] bys =new byte[1024];
int len = is.read(bys);
String str = new String(bys,0,len);
System.out.println(str);
s.close();
三次握手:
所謂三次握手(Three-Way Handshake)即建立TCP連接,就是指建立一個TCP連接時,需要客戶端和服務端總共發送3個包以確認連接的建立。在socket編程中,這一過程由客戶端執行connect來觸發,整個流程如下圖所示:

圖1 TCP三次握手
(1)第一次握手:Client將標志位SYN置為1,隨機產生一個值seq=J,並將該數據包發送給Server,Client進入SYN_SENT狀態,等待Server確認。
(2)第二次握手:Server收到數據包后由標志位SYN=1知道Client請求建立連接,Server將標志位SYN和ACK都置為1,ack=J+1,隨機產生一個值seq=K,並將該數據包發送給Client以確認連接請求,Server進入SYN_RCVD狀態。
(3)第三次握手:Client收到確認后,檢查ack是否為J+1,ACK是否為1,如果正確則將標志位ACK置為1,ack=K+1,並將該數據包發送給Server,Server檢查ack是否為K+1,ACK是否為1,如果正確則連接建立成功,Client和Server進入ESTABLISHED狀態,完成三次握手,隨后Client與Server之間可以開始傳輸數據了。
四次揮手:
所謂四次揮手即終止TCP連接,就是指斷開一個TCP連接時,需要客戶端和服務端總共發送4個包以確認連接的斷開。在socket編程中,這一過程由客戶端或服務端任一方執行close來觸發,整個流程如下圖所示:

圖2 TCP四次揮手
由於TCP連接時全雙工的,因此,每個方向都必須要單獨進行關閉,這一原則是當一方完成數據發送任務后,發送一個FIN來終止這一方向的連接,收到一個FIN只是意味着這一方向上沒有數據流動了,即不會再收到數據了,但是在這個TCP連接上仍然能夠發送數據,直到這一方向也發送了FIN。首先進行關閉的一方將執行主動關閉,而另一方則執行被動關閉,上圖描述的即是如此。
(1)第一次揮手:Client發送一個FIN,用來關閉Client到Server的數據傳送,Client進入FIN_WAIT_1狀態。
(2)第二次揮手:Server收到FIN后,發送一個ACK給Client,確認序號為收到序號+1(與SYN相同,一個FIN占用一個序號),Server進入CLOSE_WAIT狀態。
(3)第三次揮手:Server發送一個FIN,用來關閉Server到Client的數據傳送,Server進入LAST_ACK狀態。
(4)第四次揮手:Client收到FIN后,Client進入TIME_WAIT狀態,接着發送一個ACK給Server,確認序號為收到序號+1,Server進入CLOSED狀態,完成四次揮手。