1. 程式人生 > >TCP的連接和中止

TCP的連接和中止

網絡管理

介紹

TCP是一個面向連接的協議,所以在連接雙方發送數據之前,都需要先建立一條連接。這和IP協議,IMCP協議完全不同。IP協議,IMCP協議都只是發送數據而已,大多數都不關心發送的數據是不是送到,UDP協議尤其明顯,因為UDP都不用考慮數據分片。


正文

首先介紹TCP包(如圖1),然後通過TCP包來了解它的連接和中止過程。


技術分享

圖1

上圖中的字段需要重點介紹一下:

(1)源端口、目標端口:計算機上的進程要和其他進程通信是要通過計算機端口的,而一個計算機端口某個時刻只能被一個進程占用,所以通過指定源端口和目標端口,就可以知道是哪兩個進程需要通信。源端口、目標端口是用16位表示的,可推算計算機的端口個數為2^16個

(2)序號:Seq序號,占32位,用來標識從TCP源端向目的端發送的字節流,發起方發送數據時對此進行標記。

(3)確認號:Ack序號,占32位,只有ACK標誌位為1時,確認序號字段才有效,Ack=Seq+1。也就是告訴發送發:我希望你(指發送方)下次發送的數據的第一個字節數據的編號是這個確認號。

(4)數據偏移:表示TCP報文段的首部長度,共4位,它指出TCP報文段的數據起始處離距離TCP報文段的起始處有多遠。

(5)標誌位:共6個,即URG、ACK、PSH、RST、SYN、FIN等,具體含義如下:

A、URG:緊急指針(urgent pointer),只有當URG=1時才有效。

B、ACK:確認序號有效,只有當ACK=1時,前面的確認序號才有效。

C、PSH:接收方應該盡快將這個數據交給應用層,為接收後續數據騰出空間。如果結果為1,則表示對方應當立即把數據提交給應用層,而不是緩存,如果不收走數據,就會一直停留在TCP接收緩沖區。

D、RST:重新連接。如果收到RST=1的報文,說明與主機連接出現了嚴重錯誤,必須釋放連接,然後重新建立連接。

E、SYN:發起一個新的連接。當SYN=1,ACK=0時,這是一個請求建立連接的報文段;當SYN=1,ACK=1時,表示對方同意建立連接。

F、FIN:釋放一個連接。當FIN=1,即告訴對方:“我的數據已發送完畢,你可以釋放連接了”。

(6)窗口大小:從本報文段的確認號開始允許對方發送的數據量。

(7)校驗和:提供額外的可靠性。

(8)緊急指針:標記緊急數據在數據字段中的位置。

(9)選項部分:其最大長度可根據TCP首部長度進行推算。

需註意的是:

①、不要將確認序號Ack與標誌位中的ACK搞混淆;

②、確認方Ack=發起方Req+1,兩端配對。

結束了對TCP包的首部了解,現在我們開始進行TCP的連接和中止。簡單來說TCP連接的建立可以稱為三次握手,而連接的中止則可以叫做四次揮手

三次握手

所謂三次握手即建立TCP連接,就是指建立一個TCP連接時,需要客戶端和服務端總共發送3個包以確認連接的建立。在socket編程中,這一過程由客戶端執行connect來觸發,整個流程如下圖所示:

技術分享

圖2

過程:

(1)第一次握手:Client將標誌位SYN置為1,隨機產生一個值seq=x,並將該數據包發送給Server,Client進入SYN_SENT狀態,等待Server確認。

(2)第二次握手:Server收到數據包後由標誌位SYN=1知道Client請求建立連接,Server將標誌位SYN和ACK都置為1,ack=x+1,隨機產生一個值seq=y,並將該數據包發送給Client以確認連接請求,Server進入SYN_RCVD狀態。

(3)第三次握手:Client收到確認後,檢查ack是否為y+1,ACK是否為1,如果正確則將標誌位ACK置為1,ack=y+1,並將該數據包發送給Server,Server檢查ack是否為y+1,ACK是否為1,如果正確則連接建立成功,Client和Server進入ESTABLISHED狀態,完成三次握手,隨後Client與Server之間可以開始傳輸數據了。

狀態切換:

客戶端:

Closed--> SYN-SENT --> ESTAB-LISHED

關閉----> 同步已發送 --> 已建立連接

服務器端:

Closed--> LISTEN --> SYN-RCVD --> ESTAB-LISHED

關閉----> 收聽 --> 同步收到 --> 已建立連接

簡單來說就是:在建立連接的時候,客戶端首先向服務器申請打開某一個端口(用SYN段等於1的TCP報文),然後服務器端發回一個ACK報文通知客戶端請求報文收到,客戶端收到確認報文以後再次發出確認報文確認剛才服務器端發出的確認報文(繞口麽),至此,連接的建立完成。這就叫做三次握手。如果打算讓雙方都做好準備的話,一定要發送三次報文,而且只需要三次報文就可以了。

四次揮手

所謂四次揮手即終止TCP連接,就是指斷開一個TCP連接時,需要客戶端和服務端總共發送4個包以確認連接的斷開。在socket編程中,這一過程由客戶端或服務端任一方執行close來觸發,如下圖:


技術分享

圖3

過程:

(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狀態,完成四次揮手。

狀態切換:

客戶端:

ESTAB-LISHED --> FIN-WAIT-1 -- > FIN-WAIT-2 --> TIME-WAIT(等待2MSL) --> CLOSED

建立連接狀態 終止等待1 終止等待2 時間等待 關閉

服務器端:

ESTAB-LISHED --> CLOSE-WAIT --> LAST-ACK --> CLOSED

建立連接狀態 關閉等待 最後確認 關閉

TCP的連接是全雙工(可以同時發送和接收)連接,因此在關閉連接的時候,必須關閉傳和送兩個方向上的連接。客戶機給服務器一個FIN為1的TCP報文,然後服務器返回給客戶端一個確認ACK報文,並且發送一個FIN報文,當客戶機回復ACK報文後(四次握手),連接就結束了。

上面是一方主動關閉,另一方被動關閉的情況,實際中還會出現同時發起主動關閉的情況,具體流程如下圖:


技術分享

圖4

流程和狀態在上圖中已經很明了了,在此不再描述,可以參考前面的四次揮手解析步驟。

OK~是不是很難懂的感覺?那我們來說的“人性化點的”吧

三次握手流程:

客戶端發個請求“開門吶,我要進來”給服務器

服務器發個“進來吧,我去給你開門”給客戶端

客戶端有很客氣的發個“謝謝,我要進來了”給服務器

四次揮手流程:

客戶端發個“時間不早了,我要走了”給服務器,等服務器起身送他

服務器聽到了,發個“我知道了,那我送你出門吧”給客戶端,等客戶端走

服務器把門關上後,發個“我關門了”給客戶端,然後等客戶端走(哎呦餵~矯情啊)

客戶端發個“我知道了,我走了”,之後自己就走了

附加題:為什麽建立連接是三次握手,而關閉連接卻是四次揮手呢?

這是因為服務端在LISTEN狀態下,收到建立連接請求的SYN報文後,把ACK和SYN放在一個報文裏發送給客戶端。而關閉連接時,當收到對方的FIN報文時,僅僅表示對方不再發送數據了但是還能接收數據,乙方也未必全部數據都發送給對方了,所以乙方可以立即close,也可以發送一些數據給對方後,再發送FIN報文給對方來表示同意現在關閉連接,因此,乙方ACK和FIN一般都會分開發送。


TCP的連接和中止