1. 程式人生 > >TCP三次握手和四次揮手,及TCP協議埠狀態說明:CLOSE-WAIT、TIME-WAIT 、LISTENING、SYN_SENT、ESTABLISHED、LAST-ACK ...

TCP三次握手和四次揮手,及TCP協議埠狀態說明:CLOSE-WAIT、TIME-WAIT 、LISTENING、SYN_SENT、ESTABLISHED、LAST-ACK ...

TCP三次握手和四次揮手狀態圖:

三次握手:

第一次
第一次握手:建立連線時,客戶端傳送SYN包(syn=j)到伺服器,並進入SYN_SENT狀態,等待伺服器確認;SYN:同步序列編號(Synchronize Sequence Numbers)。
第二次
第二次握手:伺服器收到syn包,必須確認客戶的SYN(ack=j+1),同時自己也傳送一個SYN包(syn=k),即SYN+ACK包,此時伺服器進入SYN_RECV狀態;
第三次
第三次握手:客戶端收到伺服器的SYN+ACK包,向伺服器傳送確認包ACK(ack=k+1),此包傳送完畢,客戶端和伺服器進入ESTABLISHED(TCP連線成功)狀態,完成三次握手。
完成三次握手,客戶端與伺服器開始傳送資料。

 

四次揮手:

由於TCP連線是全雙工的,因此每個方向都必須單獨進行關閉。這原則是當一方完成它的資料傳送任務後就能傳送一個FIN來終止這個方向的連線。收到一個 FIN只意味著這一方向上沒有資料流動,一個TCP連線在收到一個FIN後仍能傳送資料。首先進行關閉的一方將執行主動關閉,而另一方執行被動關閉。
(1) TCP客戶端傳送一個FIN,用來關閉客戶到伺服器的資料傳送。
(2) 伺服器收到這個FIN,它發回一個ACK,確認序號為收到的序號加1。和SYN一樣,一個FIN將佔用一個序號。
(3) 伺服器關閉客戶端的連線,傳送一個FIN給客戶端。
(4) 客戶端發回ACK報文確認,並將確認序號設定為收到序號加1。

 

CLOSED:
這個沒什麼好說的了,表示初始狀態。


LISTENING(服務端狀態):
這個也是非常容易理解的一個狀態,表示伺服器端的某個SOCKET處於監聽狀態,可以接受連線了。也即提供某種服務,偵聽遠方TCP埠的連線請求,當提供的服務沒有被連線時,處於LISTENING狀態,埠是開放的,等待被連線。


SYN_RCVD (服務端狀態):
這個狀態表示接受到了SYN報文,在正常情況下,這個狀態是伺服器端的SOCKET在建立TCP連線時的三次握手會話過程中的一箇中間狀態,很短暫,基本上用netstat你是很難看到這種狀態的,除非你特意寫了一個客戶端測試程式,故意將三次TCP握手過程中最後一個ACK報文不予傳送。因此這種狀態時,當收到客戶端的ACK報文後,它會進入到ESTABLISHED狀態。


SYN_SENT(客戶端狀態):
這個狀態與SYN_RCVD遙相呼應,當客戶端SOCKET執行CONNECT連線時,它首先發送SYN報文,因此也隨即它會進入到了SYN_SENT狀態,並等待服務端的傳送三次握手中的第2個報文。SYN_SENT狀態表示客戶端已傳送SYN報文。


ESTABLISHED:
這個容易理解了,表示連線已經建立了。


FIN_WAIT_1(客戶端狀態):
這個狀態要好好解釋一下,其實FIN_WAIT_1和FIN_WAIT_2狀態的真正含義都是表示等待對方的FIN報文。而這兩種狀態的區別是:FIN_WAIT_1狀態實際上是當SOCKET在ESTABLISHED狀態時,它想主動關閉連線,向對方傳送了FIN報文,此時該SOCKET即進入到FIN_WAIT_1狀態。而當對方迴應ACK報文後,則進入到FIN_WAIT_2狀態,當然在實際的正常情況下,無論對方何種情況下,都應該馬上回應ACK報文,所以FIN_WAIT_1狀態一般是比較難見到的,而FIN_WAIT_2狀態還有時常常可以用netstat看到。


FIN_WAIT_2(客戶端狀態):
上面已經詳細解釋了這種狀態,實際上FIN_WAIT_2狀態下的SOCKET,表示半連線,也即有一方要求close連線,但另外還告訴對方,我暫時還有點資料需要傳送給你,稍後再關閉連線。從遠端TCP等待連線中斷請求,主動關閉端接到ACK後,就進入了FIN-WAIT-2 .這是在關閉連線時,客戶端和伺服器兩次握手之後的狀態,是著名的半關閉的狀態了,在這個狀態下,應用程式還有接受資料的能力,但是已經無法傳送資料,但是也有一種可能是,客戶端一直處於FIN_WAIT_2狀態,而伺服器則一直處於WAIT_CLOSE狀態,而直到應用層來決定關閉這個狀態。

 


TIME_WAIT(客戶端狀態):
表示收到了對方的FIN報文,併發送出了ACK報文,就等2MSL後即可回到CLOSED可用狀態了。如果FIN_WAIT_1狀態下,收到了對方同時帶FIN標誌和ACK標誌的報文時,可以直接進入到TIME_WAIT狀態,而無須經過FIN_WAIT_2狀態。

注:MSL(Maximum Segment Lifetime):即報文段最大生存時間。

為什麼客戶端在TIME-WAIT狀態必須等待2MSL時間呢? 
第一,為了保證客戶端傳送的最後一個ACK報文能夠到達服務端。這個ACK報文段有可能丟失,因而使處在LAST-ACK狀態的服務端收不到對已傳送的FIN+ACK報文段的確認。服務端會超時重傳這個FIN+ACK報文段,而客戶端就能在2MSL時間內收到這個重傳的FIN+ACK報文段。如果客戶端在TIME-WAIT狀態不等待一段時間,而是在傳送完ACK報文段後就立即釋放連線,就無法收到服務端重傳的FIN+ACK報文段,因而也不會再發送一次確認報文段。這樣,服務端就無法按照正常的步驟進入CLOSED狀態。 
第二,客戶端在傳送完ACK報文段後,再經過2MSL時間,就可以使本連線持續的時間所產生的所有報文段都從網路中消失。這樣就可以使下一個新的連線中不會出現這種舊的連線請求的報文段。 


CLOSING:
這種狀態比較特殊,實際情況中應該是很少見,屬於一種比較罕見的例外狀態。正常情況下,當你傳送FIN報文後,按理來說是應該先收到(或同時收到)對方的ACK報文,再收到對方的FIN報文。但是CLOSING狀態表示你傳送FIN報文後,並沒有收到對方的ACK報文,反而卻也收到了對方的FIN報文。什麼情況下會出現此種情況呢?其實細想一下,也不難得出結論:那就是如果雙方几乎在同時close一個SOCKET的話,那麼就出現了雙方同時傳送FIN報文的情況,也就會出現CLOSING狀態,表示雙方都正在關閉SOCKET連線。


CLOSE_WAIT(服務端狀態):
這種狀態的含義其實是表示在等待關閉。怎麼理解呢?當對方close一個SOCKET後傳送FIN報文給自己,你係統毫無疑問地會迴應一個ACK報文給對方,此時則進入到CLOSE_WAIT狀態。接下來呢,實際上你真正需要考慮的事情是檢視你是否還有資料傳送給對方,如果沒有的話,那麼你也就可以close這個SOCKET,傳送FIN報文給對方,也即關閉連線。所以你在CLOSE_WAIT狀態下,需要完成的事情是等待你去關閉連線。


LAST_ACK(服務端狀態):
這個狀態還是比較容易好理解的,它是被動關閉一方在傳送FIN報文後,最後等待對方的ACK報文。當收到ACK報文後,也即可以進入到CLOSED可用狀態了。

 

狀態遷移過程:

  a、客戶端:

    CLOSED->SYN_SENT->ESTABLISHED->FIN_WAIT_1->FIN_WAIT_2->TIME_WAIT->CLOSED

  b、服務端

    CLOSED->LISTENING->SYN_RECEIVED->ESTABLISHED->CLOSE_WAIT->LAST_ACK->CLOSED

在眾多狀態中,經常關注的有兩個:TIME_WAIT、CLOSE_WAIT。

參考連結:https://www.cnblogs.com/jessezeng/p/5617105.html