說說你對“三次握手”、“四次揮手”的理解

2023.03.07
說說你對“三次握手”、“四次揮手”的理解

經過三次握手的過程,客戶端和服務端之間的確定連接正常,接下來進入ESTABLISHED狀態,服務端和客戶端就可以快樂地通信了。

​參考答案:

我們都知道TCP 是面向連接的,三次握手就是用來建立連接的,四次握手就是用來斷開連接的。

三次握手

先上圖:


白話文理解

  1. 我能主動給你打·電話嗎?
  2. 當然可以啊!那我也能給你打電話嗎?
  3. 可以的呢,建⽴連接成功!


我們來看一下三次握手的過程:

  • 一開始,客戶端和服務端都處於CLOSED 狀態。客戶端主動打開連接,服務端被動打開連接,結束CLOSED 狀態,開始監聽,進入LISTEN 狀態。

一次握手

  • 客戶端會隨機初始化序號(client_isn),將此序號置於TCP 首部的「序號」字段中,同時把SYN 標誌位置為1 ,表示SYN 報文。接著把第一個SYN 報文發送給服務端,表示向服務端發起連接,該報文不包含應用層數據,之後客戶端處於SYN-SENT 狀態。

二次握手

  • 服務端收到客戶端的SYN 報文後,首先服務端也隨機初始化自己的序號(server_isn),將此序號填入TCP 首部的「序號」字段中,其次把TCP 首部的「確認應答號」字段填入client_isn + 1, 接著把SYN 和ACK 標誌位置為1。最後把該報文發給客戶端,該報文也不包含應用層數據,之後服務端處於SYN-RCVD 狀態。

三次握手

  • 客戶端收到服務端報文後,還要向服務端回應最後一個應答報文,首先該應答報文TCP 首部ACK 標誌位置為1 ,其次「確認應答號」字段填入server_isn + 1 ,最後把報文發送給服務端,這次報文可以攜帶客戶到服務器的數據,之後客戶端處於ESTABLISHED 狀態。

好了,經過三次握手的過程,客戶端和服務端之間的確定連接正常,接下來進入ESTABLISHED狀態,服務端和客戶端就可以快樂地通信了。

這裡有個動態過程的圖示:


這裡有個小細節,第三次握手是可以攜帶數據的,這是面試常問的點。

那麼為什麼要三次握手呢?兩次不行嗎?

  • 為了防止服務器端開啟一些無用的連接增加服務器開銷
  • 防止已失效的連接請求報文段突然又傳送到了服務端,因而產生錯誤。

由於網絡傳輸是有延時的(要通過網絡光纖和各種中間代理服務器),在傳輸的過程中,比如客戶端發起了SYN=1 的第一次握手。

如果服務器端就直接創建了這個連接並返回包含SYN、ACK 和Seq 等內容的數據包給客戶端,這個數據包因為網絡傳輸的原因丟失了,丟失之後客戶端就一直沒有接收到服務器返回的數據包。

如果沒有第三次握手告訴服務器端客戶端收的到服務器端傳輸的數據的話,服務器端是不知道客戶端有沒有接收到服務器端返回的信息的。服務端就認為這個連接是可用的,端口就一直開著,等到客戶端因超時重新發出請求時,服務器就會重新開啟一個端口連接。

這樣一來,就會有很多無效的連接端口白白地開著,導致資源的浪費。

這個過程可理解為:

還有一種情況是已經失效的客戶端發出的請求信息,由於某種原因傳輸到了服務器端,服務器端以為是客戶端發出的有效請求,接收後產生錯誤。


所以我們需要“第三次握手”來確認這個過程:

通過第三次握手的數據告訴服務端,客戶端有沒有收到服務器“第二次握手”時傳過去的數據,以及這個連接的序號是不是有效的。若發送的這個數據是“收到且沒有問題”的信息,接收後服務器就正常建立TCP 連接,否則建立TCP 連接失敗,服務器關閉連接端口。由此減少服務器開銷和接收到失效請求發生的錯誤。

數據傳輸​


四次揮手​


白話文理解

  1. 我們分⼿吧
  2. 收到分⼿的信息
  3. 好吧,分就分吧
  4. ⾏,那就到這⾥了

為了防⽌最終的ACK 丟失,發送ACK 後需要等待⼀段時間,因為如果丟包服務端需要重新發送FIN 包,如果

客戶端已經closed ,那麼服務端會將結果解析成錯誤。從⽽在⾼並發⾮⻓連接的場景下會有⼤量端⼝被佔

雙方都可以主動斷開連接,斷開連接後主機中的「資源」將被釋放。

上圖是客戶端主動關閉連接:

一次揮手

  • 客戶端打算關閉連接,此時會發送一個TCP 首部FIN 標誌位被置為1 的報文,也即FIN 報文,之後客戶端進入FIN_WAIT_1 狀態。

二次揮手

  • 服務端收到該報文後,就向客戶端發送ACK 應答報文,接著服務端進入CLOSED_WAIT 狀態。

三次揮手

  • 客戶端收到服務端的ACK 應答報文後,之後進入FIN_WAIT_2 狀態。等待服務端處理完數據後,也向客戶端發送FIN 報文,之後服務端進入LAST_ACK 狀態。

四次揮手

  • 客戶端收到服務端的FIN 報文後,回一個ACK 應答報文,之後進入TIME_WAIT 狀態
  • 服務器收到了ACK 應答報文後,就進入了CLOSED 狀態,至此服務端已經完成連接的關閉。
  • 客戶端在經過2MSL 一段時間後,自動進入CLOSED 狀態,至此客戶端也完成連接的關閉。

每個方向都需要一個FIN 和一個ACK,因此通常被稱為四次揮手。

為什麼要揮手四次?

  • 關閉連接時,客戶端向服務端發送FIN 時,僅僅表示客戶端不再發送數據了但是還能接收數據。
  • 服務器收到客戶端的FIN 報文時,先回一個ACK 應答報文,而服務端可能還有數據需要處理和發送,等服務端不再發送數據時,才發送FIN 報文給客戶端來表示同意現在關閉連接。

從上面過程可知,服務端通常需要等待完成數據的發送和處理,所以服務端的ACK 和FIN 一般都會分開發送,從而比三次握手導致多了一次。

為什麼客戶端在TIME-WAIT 階段要等2MSL?

為的是確認服務器端是否收到客戶端發出的ACK 確認報文,當客戶端發出最後的ACK 確認報文時,並不能確定服務器端能夠收到該段報文。

所以客戶端在發送完ACK 確認報文之後,會設置一個時長為2MSL 的計時器。

MSL 指的是Maximum Segment Lifetime:一段TCP 報文在傳輸過程中的最大生命週期。

2MSL 即是服務器端發出為FIN 報文和客戶端發出的ACK 確認報文所能保持有效的最大時長。

服務器端在1MSL 內沒有收到客戶端發出的ACK 確認報文,就會再次向客戶端發出FIN 報文:

  • 如果客戶端在2MSL 內,再次收到了來自服務器端的FIN 報文,說明服務器端由於各種原因沒有接收到客戶端發出的ACK 確認報文。

客戶端再次向服務器端發出ACK 確認報文,計時器重置,重新開始2MSL 的計時。

  • 否則客戶端在2MSL 內沒有再次收到來自服務器端的FIN 報文,說明服務器端正常接收了ACK 確認報文,客戶端可以進入CLOSED 階段,完成“四次揮手”。

所以,客戶端要經歷時長為2SML 的TIME-WAIT 階段;這也是為什麼客戶端比服務器端晚進入CLOSED 階段的原因。