TCP的三次握手與四次揮手

資料參考於

1.《Linux高性能服務器編程》

2.https://blog.csdn.net/qq_38950316/article/details/81087809

基礎的協議知識需要牢牢掌握,這樣才能抓住問題的本質。

一.TCP頭部結構

要全面瞭解TCP,首先了解一下TCP的頭部結構組成.

  1. 兩個16位端口號:分別告知主機該報文段來自哪裏,以及傳給哪個上層協議或者應用程度。

  2. 32位序列號(sequence number):一次TCP通信從連接到斷開過程中一個傳輸方向的字節流編號。TCP是全雙工的。

  3. 32位確認號:用作對另一方發來的TCP報文段的響應。

  4. 4位頭部長度

  5. 6位標誌位,非常重要

    字段 含義 URG 緊急指針是否有效。爲1,表示某一位需要被優先處理 ACK 確認號是否有效,一般置爲1。 PSH 提示接收端應用程序立即從TCP緩衝區把數據讀走。 RST 對方要求重新建立連接,復位。 SYN 請求建立連接,並在其序列號的字段進行序列號的初始值設定。建立連接,設置爲1 FIN 希望斷開連接

  6. 16位窗口大小,用於控制TCP的流量。

  7. 16位校檢和。

  8. 16位緊急指針。

二.TCP連接的建立與關閉

  1. 何爲三次握手

    三次握手是建立TCP可靠連接的重要過程,分三步走。

    img

            

  • 第一次握手,客戶端向服務器端發送TCP報文段含有SYN標誌,這是一個同步報文段,表示客戶端向服務器端發送連接請求。此時,服務器端被動地等待客戶端連接,這個狀態被稱爲LISTEN狀態。一旦監聽到某個連接請求,將請求送進內核等待隊列中,並向客戶端發送帶SYN標誌的確認報文段。此時,客戶端進入SYN_SENT狀態。

  • 第二次握手,服務器收到SYN包後,必須確認客戶的SYN,發送ack=客戶端序列值x+1,並且還需要發送自己的SYN,即SYN+ACK包,服務器進入SYN_RCVD狀態

  • 第三次握手,客戶端在SYN_SENT狀態下收到了服務器的SYN+ACK包,再向服務器發送確認包ACK(ack=服務器序列值y+1),此包發送完畢後,兩者進入ESTABLISHED狀態,至此,TCP的連接就算建立完成了。

 

2.何爲四次揮手

img

  • 第一次揮手,在ESTABLISHED狀態下的客戶端向服務器端發送包含FIN標誌的TCP報文段,這是一個結束報文段,即客戶端要求斷開連接。和建立連接一樣,需要發送一個序列號u,發送完成後客戶端進入FIN_WAIT1狀態。TCP規定,FIN報文段即使不攜帶數據,也要消耗一個序號。

  • 第二次揮手,服務器端用客戶端發送的FIN標誌報文段來確認該結束報文段,發出確認報文,ACK=1,ack=u+1,同時發送自己的序列號v,此時,服務器端進入CLOSE_WAIT狀態,這是一個半關閉狀態:TCP服務器通知高層的應用進程,客戶端向服務器的方向就釋放了,這時候處於半關閉狀態即客戶端已經沒有數據要發送了,但是服務器若發送數據,客戶端依然要接受。這個狀態還要持續一段時間,也就是整個CLOSE-WAIT狀態持續的時間。

  • 第三次揮手,客戶端收到第二次揮手的確認報文後會進入FIN_WAIT2狀態,這個狀態是在等待服務器端發送連接釋放報文。服務器將最後的數據發送完畢後,就向客戶端發送連接釋放報文,FIN=1,ack=u+1,由於在半關閉狀態,服務器很可能又發送了一些數據,假定此時的序列號爲seq=w,此時,服務器就進入了LAST-ACK(最後確認)狀態,等待客戶端的確認。

  • 第四次揮手,客戶端收到連接釋放報文後,必須發送確認報文,ACK=1,seq=u+1,ack=w+1,發送完成後客戶端就會進入TIME_WAIT狀態。注意此時TCP連接還沒有釋放,必須2*MSL(MSL爲TCP報文的最大生存時間)時間後,當客戶端撤銷相應的TCB後,才進入CLOSED狀態。服務器只要收到了客戶端發出的確認,立即進入CLOSED狀態。同樣,撤銷TCB後,就結束了這次的TCP連接。可以看到,服務器結束TCP連接的時間要比客戶端早一些。

三.一些常見的面試問題

  • 問題1:爲什麼TCP建立連接是三次握手,斷開連接是四次揮手?

    因爲建立連接時,服務端收到客戶端的SYN請求後,可以直接發送SYN+ACK報文,ACK報文是用作應答用的,SYN報文是用於同步的。但是關閉的時候,服務器端在收到FIN標誌報文後,很可能並不會立即關閉Socket,因爲此時很有可能服務器端還需要傳輸一部分數據,TCP是全雙工的,兩邊都是可以獨立進行數據傳輸的,所以只能先發送一個ACK報文,告訴客戶端,“你的消息我知道了”,只有等服務器端所有報文傳輸完成之後,服務器才能發送FIN標誌給客戶端,告訴客戶端,可以關閉了,這樣就比建立連接多了一次揮手。

  • 問題2:爲什麼必須是三次握手,不能用兩次握手進行連接?

    回答這個問題可以再好好理解一下三次握手的內容:我發送確認報文,表明身份,你收到確認報文,表明身份並表示已經收到,此時我再確認一遍你已經收到並獲取你的身份。

    所以3次握手完成兩個重要的功能,既要雙方做好發送數據的準備工作(雙方都知道彼此已準備好)也要允許雙方就初始序列號進行協商,這個序列號在握手過程中被髮送和確認。

    而且兩次握手很有可能會發生死鎖。

    作爲例子,考慮計算機S和C之間的通信,假定C給S發送一個連接請求分組,S收到了這個分組,併發 送了確認應答分組。按照兩次握手的協定,S認爲連接已經成功地建立了,可以開始發送數據分組。可是,C在S的應答分組在傳輸中被丟失的情況下,將不知道S 是否已準備好,不知道S建立什麼樣的序列號,C甚至懷疑S是否收到自己的連接請求分組。在這種情況下,C認爲連接還未建立成功,將忽略S發來的任何數據分 組,只等待連接確認應答分組。而S在發出的分組超時後,重複發送同樣的分組。這樣就形成了死鎖。

  • 問題3:爲什麼TIME_WAIT狀態需要經過2MSL(最大報文段生存時間)才能返回到CLOSE狀態?

    TIME_WAIT狀態存在的原因有兩點:

    • 可靠地終止TCP連接

    • 保證讓遲來的TCP報文段有足夠的時間被識別並丟棄。

    所以,因爲TCP報文段的最大生存時間,所以堅持2MSL時間的TIME_WAIT狀態能夠確保網絡上兩個傳輸方向上尚未被接收到的,遲到的TCP報文段都已經消失(被中轉路由器所丟棄)。因此,一個連接的新的化身可以在2MSL時間之後安全的建立,而絕對不會接收到屬於原來的應用程序的數據,造成混亂。

  • 問題4:如果已經建立了連接,但是客戶端突然出現故障了怎麼辦?

    TCP還設有一個保活計時器,顯然,客戶端如果出現故障,服務器不能一直等下去,白白浪費資源。服務器每收到一次客戶端的請求後都會重新復位這個計時器,時間通常是設置爲2小時,若兩小時還沒有收到客戶端的任何數據,服務器就會發送一個探測報文段,以後每隔75秒鐘發送一次。若一連發送10個探測報文仍然沒反應,服務器就認爲客戶端出了故障,接着就關閉連接。

發佈了216 篇原創文章 · 獲贊 15 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章