1. 程式人生 > >TCP三次握手和四次揮手過程原理及擴充套件(一)

TCP三次握手和四次揮手過程原理及擴充套件(一)

先上圖:

 三次握手過程狀態:

         LISTEN:表示伺服器端的某個SOCKET處於監聽狀態,可以接受連線了。

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

       SYN_RCVD:這個狀態表示接收到了SYN報文,在正常情況下,這個狀態是伺服器端的SOCKET在建立TCP連線時的三次握手會話過程中的一箇中間狀態,很短暫。

      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連線,但另外還告訴對方,我暫時還有點資料需要傳遞給你(ACK資訊),稍後再關閉連線(主動方的狀態)

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

    CLOSING(比較少見):表示雙方同時關閉連線。如果雙方几乎同時呼叫close函式,那麼會出現雙方同時發生FIN報文的情況,就會出現CLOSING狀態,表示雙方都在關閉連線。這種狀態比較特殊。正常情況下,當你發生FIN報文後,是應該先收到(或同時收到)對方的ACK報文,再收到對方的FIN報文。但是CLOSING狀態表示你發生FIN報文後,並沒有收到對方的ACK報文,反而收到了對方的FIN報文。什麼情況下會出現這種情況呢?那就是:如果雙方几乎在同時close一個SOCKET的話,那麼就出現了雙方同時發生FIN報文的情況,也即出現CLOSING狀態,表示雙方都在關閉SOCKET連線。

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

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

    CLOSED:表示連線中斷。

      首先Client端傳送連線請求報文,Server端接受連線後回覆ACK報文,併為這次連線分配資源。Client端接收到ACK報文也向Server段Server端傳送ACK報文,並分配資源,這樣TCP連線就建立了。

      ACK:TCP報頭的控制位之一,對資料進行確認,確認由目的端發出,用它來告訴傳送端這個序列號之前的資料段都收到了。比如,確認號為X,則表示前X-1個數據段都收到了,只有當ACK=1時,確認號才有效。當ACK=0時,確認號無效,這時會要求重新傳資料,保證資料的完整性。

    SYN:同步序列號,TCP建立連線時將這個位置1.

    FIN:傳送端完成傳送任務位,當TCP完成資料傳輸需要斷開時,提出斷開連線的一方將這個位置1。

【注意】中斷連線端可以是Client端,也可以是Server端。

              假設Client端發起中斷連線請求,也就是傳送FIN報文。Server端接收到FIN報文後,意思是說“我Client端沒有資料要發給你了”,但是如果你還有資料沒有傳送完成,則不必急著關閉Socket,可以繼續傳送資料。所以你先發送ACK,“告訴Client端,你的請求我收到了,但我還沒有準備好,請繼續等我的訊息”。這個時候Client端就進入FIN_WAIT狀態,繼續等待Server端的FIN報文。當Server端確認資料已傳送完成,則向Client端傳送FIN報文,“告訴Client端,好了,我這邊資料傳送完成了,準備好關閉連線了”。Client接收到FIN報文後,“就知道可以關閉連線了,但是他還是不相信網路,怕Server端不知道要關閉,所以傳送ACK後進入TIME_WAIT狀態,如果Server沒有收到ACK則可以重傳”,Server端收到ACK後,就知道可以斷開連線了。Client端等待了2MSL後依舊沒有收到回覆,說明Server端已正常關閉,這時Client端也可以關閉連線了,這樣,TCP連線就關閉了。

整個過程Client端所經歷的狀態如下:

 Server端所經歷的過程如下:

【1】為什麼收到Server端的確認之後,Client端還需要進行第三次“握手”呢?

         採用三次握手是為了防止失效的連線請求報文段突然又傳到主機B,因而產生錯誤。

        已失效的連線請求報文段的產生場景:Client發出的第一個連線請求報文段並沒有丟失,而是在某個網路節點長時間的滯留了(因為網路併發量很大在某節點被阻塞了),以導致延誤到連線釋放以後的某個時間才到達Server。本來這是一個早已失效的報文段。但Server收到此失效的連線請求報文段後,就誤認為是Client再次發出的一個新的連線請求。於是向Client發出確認報文段,同意建立連線。假設不採用“三次握手”,那麼只要server端發出確認,新的連線就建立了。由於現在client並沒有發出建立連線的請求,因此也 不會理睬server的確認,也不會向server傳送資料。但server以為新的傳輸連線已經建立,並一直等待client傳送資料。這樣,server的很多資源就浪費掉了。採用“三次握手”的辦法可以防止上述現象發生。例如剛才那種情況,client不會向server的確認發出確認。server由於收不到確認,就知道client並沒有要求建立連線。主要目的是防止server端一直等待,浪費資源。

【2】為什麼要四次揮手?

      確保資料能夠完成傳輸、、

     當連線關閉時,當收到對方的FIN報文通知時,它僅僅表示對方沒有資料傳送給你了;但未必你所有的資料都全部發送給對方了,所以你可以未必會馬上關閉SOCKET,即你可能還需要傳送一些資料給對方之後,再發送FIN報文給對方來表示你同意現在可以關閉連線了,所以它這裡的ACK報文和FIN報文多數情況下都是分開發送的。

    TCP協議是一種面向連線的、可靠的、基於位元組流的運輸層通訊協議。TCP是全雙工模式,這就意味著,當主機1發出FIN報文段後,只是代表主機1已經沒有資料要傳送了,主機1告訴主機2,它的資料已經全部發送完畢了;但是,這個時候主機1還是可以接受來自主機2的資料;當主機2返回ACK報文段時,表示它已經知道主機2沒有資料傳送了,但是主機2還是可以傳送資料到主機1的,當主機2也傳送了FIN報文段時,這個時候就表示主機2也沒有資料要傳送了,就會告訴主機1,我也沒有資料要傳送了,之後彼此就會愉快的中斷這次TCP連線。

【3】建立連線的第二個syn作用是什麼?

因為客戶端傳送的syn可能過了好久才到達服務端,而此時客戶端超時重傳的SYN已經到達服務端,那麼後來的SYN就是無效的,如果不發第二個SYN查詢客戶端是否有效的話,服務端就會監聽這個延遲到達的情趣,造成資源的浪費,所以可以強制傳送一個SYN詢問客戶端之前的請求是否有效

【4】當關閉連線時最後一個SCK丟失怎麼辦?

         如果最後一個ACK丟失的話,TCP就會認為它的FIN丟失,進行重發FIN。在客戶端收到FIN後,就會設定一個2MSL計時器,2MSL計時器可以使客戶端等待足夠長的時間,使得在ACK丟失的情況下,可以等到下一個FIN的到來。如果在TIME_WAIT狀態彙總有一個新的FIN到達了,客戶端就會發送一個新的ACK,並重新設定2MSL計時器。

       如果重傳FIN到達客戶端時,客戶端已經進入到CLOSED狀態時,那麼客戶端就永遠收不到這個重傳的FIN報文段,伺服器收不到ACK,伺服器無法關閉連線。