tcp連接狀態詳解

對於linux 套接字通信,從連接建立到連接斷開,其狀態總共有11種,在三次握手和四次揮手,狀態變化比較快,在連接建立時,狀態比較穩定,下面簡單介紹一下各個狀態的情況。

狀態彙總(11種):

  1. LISTEN:偵聽來自遠方的TCP端口的連接請求

  2. SYN-SENT:再發送連接請求後等待匹配的連接請求(客戶端)

  3. SYN-RECEIVED:再收到和發送一個連接請求後等待對方對連接請求的確認(服務器)

  4. ESTABLISHED:代表一個打開的連接

  5. FIN-WAIT-1:等待遠程TCP連接中斷請求,或先前的連接中斷請求的確認

  6. FIN-WAIT-2:從遠程TCP等待連接中斷請求

  7. CLOSE-WAIT:等待從本地用戶發來的連接中斷請求

  8. CLOSING:等待遠程TCP對連接中斷的確認

  9. LAST-ACK:等待原來的發向遠程TCP的連接中斷請求的確認

  10. TIME-WAIT:等待足夠的時間以確保遠程TCP接收到連接中斷請求的確認

  11. CLOSED:沒有任何連接狀態

TCP 3次握手:

在這裏插入圖片描述
過程分析:
第1次握手:客戶端的應用進程主動打開,並向服務端發出請求報文段。其首部中:SYN=1,seq=x。
第2次握手:服務器應用進程被動打開。若同意客戶端的請求,則發回確認報文,其首部中:SYN=1,ACK=1,ack=x+1,seq=y。
第3次握手:客戶端收到確認報文之後,通知上層應用進程連接已建立,並向服務器發出確認報文,其首部:ACK=1,ack=y+1。當服務器收到客戶端的確認報文之後,也通知其上層應用進程連接已建立。

建立連接時的狀態變遷:

一開始,建立連接之前服務器和客戶端的狀態都爲CLOSED。服務器創建socket後開始監聽,變爲LISTEN狀態。客戶端請求建立連接,向服務器發送SYN報文,客戶端的狀態變爲SYN_SENT。服務器收到客戶端的報文後向客戶端發送ACK和SYN報文,此時服務器的狀態變爲SYN_RCVD。然後,客戶端收到ACK、SYN,就向服務器發送ACK,客戶端狀態變爲ESTABLISHED,服務器收到客戶端的ACK後也變爲ESTABLISHED。此時,3次握手完成,連接建立!

TCP 4次揮手:
在這裏插入圖片描述
(1) TCP客戶端發送一個FIN,用來關閉客戶到服務器的數據傳送。
(2) 服務器收到這個FIN,它發回一個ACK,確認序號爲收到的序號加1。和SYN一樣,一個FIN將佔用一個序號。
(3) 服務器關閉客戶端的連接,發送一個FIN給客戶端。
(4) 客戶端發回ACK報文確認,並將確認序號設置爲收到序號加1。

斷開連接時的狀態變遷

由於tcp連接是全雙工的,斷開連接會比建立連接麻煩一點點。客戶端先向服務器發送FIN報文,請求斷開連接,其狀態變爲FIN_WAIT1。服務器收到FIN後向客戶端發生ACK,服務器狀態變爲CLOSE_WAIT。客戶端收到ACK後就進入FIN_WAIT2狀態。此時連接已經斷開了一半了。如果服務器還有數據要發送給客戶端,就會繼續發送。直到發完了,就發送FIN報文,此時服務器進入LAST_ACK狀態。客戶端收到服務器的FIN後,馬上發送ACK給服務器,此時客戶端進入TIME_WAIT狀態,再過了2MSL長的時間後進入CLOSED狀態。服務器收到客戶端的ACK就進入CLOSED狀態。
至此,還有一個狀態沒有提及:CLOSING狀態。CLOSING狀態表示客戶端發生了FIN,但沒有收到服務器的ACK,卻收到了服務器的FIN。這種情況發生在服務器發送的ACK丟包的時候,因爲網絡傳輸有時會有意外。

下面介紹一下各個狀態:

  1. CLOSED:

    表示初始狀態。

  2. LISTEN:

    服務器端的某個SOCKET處於監聽狀態

  3. SYN_RCVD:

    這個狀態表示接受到了SYN報文,在正常情況下,這個狀態是服務器端的SOCKET在建立TCP連接時的三次握手會話過程中的一箇中間狀態,很短暫,基本上用netstat是很難看到這種狀態的,因此這種狀態時,當收到客戶端的ACK報文後,它會進入到ESTABLISHED狀態。

  4. SYN_SENT:

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

  5. ESTABLISHED:
    表示連接已經建立了。

  6. 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看到。

  7. FIN_WAIT_2:

    上面已經詳細解釋了這種狀態,實際上FIN_WAIT_2狀態下的SOCKET,表示半連接,也即有一方要求close連接,但另外還告訴對方,我暫時還有點數據需要傳送給你,稍後再關閉連接這就是著名的半關閉的狀態了,這是在關閉連接時,客戶端和服務器兩次握手之後的狀態。在這個狀態下,應用程序還有接受數據的能力,但是已經無法發送數據,但是也有一種可能是,客戶端一直處於FIN_WAIT_2狀態,而服務器則一直處於WAIT_CLOSE狀態,而直到應用層來決定關閉這個狀態

  8. TIME_WAIT:

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

  9. CLOSING:

    這裏先說一下另一種狀態(同時打開),RST是另一種關閉連接的方式,應用程序應該可以判斷RST包的真實性,即是否爲異常中止。而同時打開和同時關閉則是兩種特殊的TCP狀態,發生的概率很小。
    下面說closing狀態

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

  10. CLOSE_WAIT:

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

  11. LAST_ACK:

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章