詳解TCP一:三次握手、四次揮手

今天你做題了嗎發表於2020-07-19

TCP協議同樣是運輸層的協議,掌握TCP重點要關注這幾個問題:順序問題、丟包問題、連線維護、流量控制、擁塞控制。先解析下TCP報文段結構,相比於UDP要複雜很多。

  • 首先還是兩個埠號,對應著具體的應用程式。
  • 序號指的是包的序號,為了解決包亂序問題。
  • 發出去的包應該有確認,如果接收方沒有收到就應該重新傳送,直到送達。確認序號解決的是丟包問題。
  • 由於TCP選項欄位的原因,TCP首部長度是可變的。通常選項欄位為空,所以TCP首部欄位長度一般是20位元組。
  • 視窗大小用於流量控制,用來指示接收方願意接收的位元組數量。
  • 選項欄位用於傳送方與接收方協商最大報文段長度或者在高速網路環境下用作視窗調節因子。
  • 標誌欄位由6個狀態位組成,SYN是發起一個連線、ACK是回覆、RST是重新連線、FIN是結束連線。URG表示報文段裡存在著被髮送端的上層實體置為“緊急” 的資料,緊急資料的最後一個位元組由16b位的緊急資料指標欄位指出。實際使用中,PSH、URG和緊急資料指標用不到。

所有的問題起於連線,先關注連線管理問題。TCP的連線建立分為三步,通常稱為三次握手。具體的的狀態是:

 

客戶端收到服務端傳送的 SYN 和 ACK 之後,傳送ACK 的 ACK,之後處於 ESTABLISHED 狀態,因為它一發一收成功了。服務端收到 對ACK 的 ACK 之後,處於 ESTABLISHED 狀態,因為它也一發一收了。

為什麼不是兩次、四次或者更多次?

  比如AB要建立連線,A發起一個連線但連線請求沒有響應,可能包丟了、包繞彎路了、超時了等等,A於是繼續給B發包,終於B收到了請求包但A並不知道,所以A可能還會繼續發。B收到包之後,知道了A存在並且要和它建立連線。如果B不想建立連線,A重試一會後放棄,連線建立失敗沒有問題。如果B願意建立連線,那就會發應答包給A。同樣這個應答包會和請求包出現一樣的問題,那麼對於B不能認為連線建立好了。

  B傳送的應答包可能會傳送多次,只要有一次到達A,那麼A就認為連線已經建立了,因為A的訊息有去有回,相當於兩次握手。假如這時候連線已經建立,並且做了簡單通訊後,結束了連線。上面講了A要建立連線的時候,可能會傳送多個請求包。有的請求包繞了一大圈又回來了,B 會認為這也是一個正常的的請求,再次建立連線,但這個連線不會正常接發資料、也不會終結,B就一直等待。A發的訊息有去有回,但B發出的訊息沒有回,所以兩次握手肯定不行。其實三次握手中,A發給B回覆的回覆也會丟、繞路或者B掛了,按照這個邏輯B還要再發個確認就變成了四次握手,這樣不停套娃多達幾百次也可以,但這也不能保證就可靠了。TCP連線的設計原則是雙發的訊息都有去有回就基本可以了。

  大部分情況下,A和B建立連線後會A會馬上傳送資料,如果A發給B的應答丟了,A後續傳送的資料到達時,B可以認為連線已經建立;又或者B掛了,那麼直接報錯返回B不可達資訊都沒問題。如果A就是不傳送資料,客戶端可以開啟keeplive機制,傳送探活包。服務端設定規定時間,超時了就主動關閉,釋放資源。

  TCP把資料看成一個無結構、有序的位元組流,一個報文段的序號是該報文段首位元組的位元組流編號。三次握手除了確保雙方訊息有去有回,最重要的是解決tcp包的序號問題。A、B雙方互相告知對方包的起始序號。又會有個疑問,為什麼一定要交換序號,不能從序號1開始發包嗎?假設A給B發3個包,序號為1、2、3,但3包可能繞路了,沒有正常到達B,A又重新傳送。後來A掉線了,重新連上B後又從1開始,傳送兩個包1、2,但上次出問題的包3又回來了,發給了B,B認為這就是A要發給它的下一個包,於是出現錯誤。因此每個連線都要有不同的序號,序號的起始序號每4ms加一,等遇到重複的序號要4個多小時。比如3號包繞路了,就要隔4個多小時連線的起始序號才是3,這麼長時間3號包已經無效了,因為IP包頭裡有TTL(生存時間)。

再來看四次揮手,前兩次和握手連線差不多。同樣將傳送接收方用AB表示。當B進入CLOSED-WAIT,A進入FIN-WAIT2狀態時,如果B突然掛了,那麼A會一直處於這個狀態,TCP本身沒有對這種個狀態進行處理。在Linux中可以調整 tcp_fin_timeout 引數,設定超時時間。

  如果一切正常,進行第三次揮手A收到B的主動關閉請求併傳送確認後進入TIME-WAIT狀態,為什麼需要這個狀態呢?假設A傳送完確認訊息後直接關閉,如果B沒收到這個確認訊息,那B會重發結果就是B關閉失敗。還有一種情況是A的埠空出來,但B還保持原來狀態不知道A的情況。如果 A 的埠被一個新的應用佔用了,這個新的應用會收到上個連線中 B 發過來的包,資料接收錯誤。所以A要進入TIME-WAIT狀態,並且TCP設定了等待時間2MSL(報文段最大生存時間),任何報文在網路上存在超過這個時間將被丟棄。協議規定 MSL 為 2 分鐘,實際應用中常用的是 30秒,1 分鐘和 2 分鐘等。還有一種情況是超過了2MSL,B依然沒有收到對FIN的ACK。這時即便A收到了B重發的FIN,A會直接傳送RST,表示重新開始揮手。

 

參考資料:《趣談網路協議》劉超

     《計算機網路:自頂向下方法》原書第六版 陳鳴譯

相關文章