在網路通信的浩瀚海洋中,TCP(傳輸控制協議)以其提供可靠的、面向連接的數據傳輸服務而聞名。為了確保數據能夠準確無誤地從發送方到達接收方,並避免出現混亂,TCP設計了一套精密的機制來建立和終止連接。這套機制的核心便是我們今天要深入探討的——TCP三次握手(Three-Way Handshake)和TCP四次揮手(Four-Way Wave)。
無論是您正在瀏覽網頁、收發電子郵件,還是進行在線遊戲,這些背後都離不開TCP連接的默默支撐。理解三次握手與四次揮手,不僅能幫助我們更深層次地掌握網路工作原理,也能在遇到網路問題時提供排查思路。
TCP三次握手(Three-Way Handshake):構建可靠連接的基石
TCP三次握手是客戶端與伺服器之間建立連接的過程。這個過程形象地比喻為兩個人打電話前確認彼此都準備就緒,可以聽到對方聲音的過程。它確保了雙方都能夠發送和接收數據,為後續可靠的數據傳輸奠定了基礎。
為什麼需要三次握手?
很多人會疑問,為什麼不是兩次握手呢?兩次握手,即客戶端發送一個請求,伺服器回復一個確認,然後就建立連接。然而,這種方式存在潛在的風險:
- 防止已失效的連接請求報文段突然又傳送到了伺服器,因而產生錯誤。 設想客戶端發送的第一個連接請求報文段在網路中滯留了很長時間。如果採用兩次握手,這個「遲到」的請求到達伺服器后,伺服器會立即建立連接。而此時客戶端可能早已超時並重發了新的連接請求,並已與伺服器建立了新的連接,甚至已經關閉。如果舊的請求突然到達並建立連接,伺服器會因此分配資源,導致資源浪費,甚至可能向一個已經關閉的客戶端發送數據。
- 確保雙方都具備發送和接收能力。 三次握手可以明確地驗證客戶端能發送,伺服器能接收;伺服器能發送,客戶端能接收。缺一不可,只有雙方都確認了各自的收發能力,連接才是真正可靠的。
三次握手的詳細步驟
以下是TCP三次握手的具體流程:
-
第一次握手:客戶端發送連接請求(SYN報文)
客戶端(Client)向伺服器(Server)發送一個SYN(Synchronize Sequence Number)報文段,請求建立連接。這個報文段中包含:
- SYN標誌位: 置為1,表示這是一個連接請求報文。
- 序列號(Sequence Number, SEQ): 客戶端會隨機生成一個初始序列號(Initial Sequence Number, ISN_C),例如`seq = x`。這個序列號代表客戶端打算髮送數據的第一個位元組的編號。
此時,客戶端進入
SYN_SENT(同步已發送)狀態。客戶端 → 伺服器:
SYN=1, seq=x -
第二次握手:伺服器確認並同意連接(SYN+ACK報文)
伺服器收到客戶端的SYN報文後,如果同意建立連接,會向客戶端發送一個SYN+ACK報文段作為響應。這個報文段中包含:
- SYN標誌位: 置為1,表示伺服器也請求建立連接。
- ACK標誌位: 置為1,表示對客戶端SYN報文的確認。
- 確認號(Acknowledgment Number, ACK_NUM): 伺服器會把客戶端的
seq + 1作為確認號,即ack_num = x + 1,表示伺服器已準備好接收客戶端從x + 1開始的數據。 - 序列號(Sequence Number, SEQ): 伺服器也會隨機生成一個初始序列號(ISN_S),例如`seq = y`,代表伺服器打算髮送數據的第一個位元組的編號。
此時,伺服器進入
SYN_RCVD(同步已接收)狀態。伺服器 → 客戶端:
SYN=1, ACK=1, seq=y, ack_num=x+1 -
第三次握手:客戶端發送確認(ACK報文)
客戶端收到伺服器的SYN+ACK報文後,會向伺服器發送一個ACK報文段進行最終確認。這個報文段中包含:
- ACK標誌位: 置為1,表示對伺服器SYN報文的確認。
- 確認號(Acknowledgment Number, ACK_NUM): 客戶端會把伺服器的
seq + 1作為確認號,即ack_num = y + 1,表示客戶端已準備好接收伺服器從y + 1開始的數據。 - 序列號(Sequence Number, SEQ): 客戶端的序列號為
x + 1(或繼續使用x,因為此ACK報文不攜帶數據,不消耗序列號)。
此時,客戶端進入
ESTABLISHED(已建立)狀態。伺服器收到這個ACK報文後,也進入ESTABLISHED狀態。客戶端 → 伺服器:
ACK=1, seq=x+1, ack_num=y+1
至此,TCP三次握手完成,客戶端和伺服器之間的連接正式建立,可以開始可靠的數據傳輸了。
握手過程中關鍵欄位解析
- SYN (Synchronize Sequence Numbers): 同步序列號。當SYN=1時,表示該報文段是一個連接請求或連接接受報文。
- ACK (Acknowledgment): 確認。當ACK=1時,表示確認號欄位有效。
- SEQ (Sequence Number): 序列號。當前報文段第一個位元組的序列號。
- ACK_NUM (Acknowledgment Number): 確認號。期望收到對方下一個報文段第一個位元組的序列號。
- ISN (Initial Sequence Number): 初始序列號。在TCP連接建立時由雙方隨機生成的第一個序列號。它有助於提高連接的安全性,防止猜測並減輕一些攻擊。
小貼士: 在三次握手中,只有SYN報文和帶有SYN標誌的ACK報文會消耗一個序列號。純ACK報文(不攜帶數據)不消耗序列號。一旦連接建立,每個發送的位元組都會消耗一個序列號。
TCP四次揮手(Four-Way Wave):優雅地終止連接
當客戶端或伺服器不再需要連接時,它們會通過TCP四次揮手來斷開連接。與三次握手不同,四次揮手是雙向的,因為TCP是全雙工通信,即數據可以同時在兩個方向上傳輸。任何一方都可以發起關閉連接的請求。
為什麼需要四次揮手?
TCP連接是全雙工的,這意味著客戶端和伺服器都可以獨立地發送和接收數據。當一方完成數據發送,發出FIN報文時,表示它不再有數據要發送,但它可能仍然需要接收對方的數據。因此:
- 發起方關閉它的發送通道。
- 接收方回復ACK,表示已收到關閉請求,但它的發送通道可能還有數據要發送(因為發送和接收是獨立的)。
- 當接收方也發送完所有數據后,它才會發送FIN報文來關閉它的發送通道。
- 發起方收到FIN后,再發送ACK確認。
這個過程可以看作是:甲對乙說「我沒東西要給你了」(第一次揮手),乙回應「好的,我知道了」(第二次揮手),然後乙說「我也沒有東西要給你了」(第三次揮手),甲回應「好的,我知道了」(第四次揮手)。
四次揮手的詳細步驟
假設客戶端發起關閉連接(當然,伺服器也可以發起):
-
第一次揮手:客戶端發送關閉請求(FIN報文)
客戶端的數據發送完畢后,向伺服器發送一個FIN(Finish)報文段,表示它已經沒有數據要發送了,請求關閉連接。這個報文段中包含:
- FIN標誌位: 置為1,表示發送方已完成數據發送。
- ACK標誌位: 通常也置為1,表示對之前收到數據的確認。
- 序列號(SEQ): 假設為`u`(為之前發送的最後一個位元組的序列號+1)。
- 確認號(ACK_NUM): 假設為`v`(為之前接收到的最後一個位元組的序列號+1)。
此時,客戶端進入
FIN_WAIT_1(終止等待1)狀態。客戶端 → 伺服器:
FIN=1, ACK=1, seq=u, ack_num=v -
第二次揮手:伺服器確認關閉請求(ACK報文)
伺服器收到客戶端的FIN報文後,會發送一個ACK報文段作為響應。這個報文段中包含:
- ACK標誌位: 置為1。
- 確認號(ACK_NUM):
u + 1,表示已收到客戶端的FIN報文。 - 序列號(SEQ):
v(如果伺服器此時沒有數據要發送,則保持原序列號)。
此時,伺服器進入
CLOSE_WAIT(關閉等待)狀態。這表示伺服器已收到客戶端的關閉請求,但它可能還有數據要發送給客戶端。在發送完所有數據之前,它不會關閉自己的發送通道。客戶端收到這個ACK報文後,進入
FIN_WAIT_2(終止等待2)狀態,等待伺服器發送最後的FIN報文。伺服器 → 客戶端:
ACK=1, seq=v, ack_num=u+1 -
第三次揮手:伺服器發送關閉請求(FIN報文)
當伺服器也發送完所有數據后,會向客戶端發送一個FIN報文段,表示它也準備關閉發送通道。這個報文段中包含:
- FIN標誌位: 置為1。
- ACK標誌位: 置為1。
- 序列號(SEQ): 假設為`w`(為伺服器之前發送的最後一個位元組的序列號+1)。
- 確認號(ACK_NUM):
u + 1(與第二次揮手相同)。
此時,伺服器進入
LAST_ACK(最後確認)狀態,等待客戶端的最後確認。伺服器 → 客戶端:
FIN=1, ACK=1, seq=w, ack_num=u+1 -
第四次揮手:客戶端發送最終確認(ACK報文)
客戶端收到伺服器的FIN報文後,會發送一個ACK報文段進行最終確認。這個報文段中包含:
- ACK標誌位: 置為1。
- 確認號(ACK_NUM):
w + 1,表示已收到伺服器的FIN報文。 - 序列號(SEQ):
u + 1。
此時,客戶端進入
TIME_WAIT(時間等待)狀態,並等待2MSL(最長報文段生存時間)后才關閉連接。伺服器收到這個ACK報文後,立即進入CLOSED狀態。客戶端 → 伺服器:
ACK=1, seq=u+1, ack_num=w+1
在客戶端的TIME_WAIT狀態結束后,客戶端也進入CLOSED狀態,至此整個TCP連接徹底關閉。
揮手過程中特殊狀態解析:TIME_WAIT
TIME_WAIT是TCP連接終止過程中一個非常重要的狀態,它只出現在主動關閉連接的一方(通常是客戶端)。它的存在是為了:
- 確保最後一個ACK報文到達伺服器: 即使在第四次揮手時,客戶端發送的最後一個ACK報文丟失,伺服器會因為沒有收到ACK而重發FIN報文。如果客戶端不處於
TIME_WAIT狀態而直接關閉,它就無法收到這個重發的FIN,也就無法發送ACK,伺服器將永遠處於LAST_ACK狀態。TIME_WAIT確保了客戶端有足夠的時間重新發送ACK。 - 防止「舊連接」的數據包干擾「新連接」: 在2MSL時間內,任何遲到的、屬於該連接的數據包都會被丟棄。這防止了在同一個埠上建立新連接時,遲到的舊連接數據包被新連接錯誤地接收,造成數據混淆。
MSL (Maximum Segment Lifetime): 最長報文段生存時間,指一個報文段在網路中能夠存活的最長時間。通常設置為30秒、1分鐘或2分鐘。因此,2MSL的時間意味著報文段在網路中往返一趟並能及時被處理所需的最長時間。
儘管
TIME_WAIT狀態對於TCP的可靠性至關重要,但如果系統中存在大量處於TIME_WAIT狀態的連接,可能會導致埠資源耗盡,從而影響新連接的建立。在某些高併發伺服器場景下,會通過配置系統參數來調整TIME_WAIT的持續時間或允許重用TIME_WAIT埠。
TCP握手與揮手:異同點剖析
雖然三次握手和四次揮手都是TCP連接生命周期中的關鍵階段,但它們有著不同的目的和實現細節。
共同點:
- 都使用SYN、ACK、FIN等TCP標誌位來控制流程。
- 都涉及序列號和確認號,以確保報文的有序和可靠傳輸。
- 都包含狀態轉換,描述連接在不同階段的生命周期。
不同點:
- 目的: 握手是為了建立連接,揮手是為了終止連接。
- 報文數量: 握手通常是三次報文,揮手通常是四次報文。
- 標誌位組合:
- 握手過程中主要是SYN和ACK的組合。
- 揮手過程中主要是FIN和ACK的組合。
- 原因: 握手只需要確認雙方的收發能力,而揮手需要分別關閉雙方的發送通道,因為TCP是全雙工的,一端關閉發送不代表立刻停止接收,也不代表另一端已無數據發送。
- TIME_WAIT狀態: 揮手過程中(主動關閉方)會進入
TIME_WAIT狀態,而握手過程沒有類似狀態。
理解這些差異對於調試網路問題和優化網路應用程序性能至關重要。
常見問題 (FAQ)
以下是一些關於TCP三次握手與四次揮手過程的常見問題及解答。
為何TCP三次握手不能減少為兩次?兩次握手最大的問題在於無法有效防止「已失效的連接請求報文段」對伺服器造成干擾。假設客戶端發送的第一個連接請求在網路中滯留,在客戶端重發新請求並建立連接后,舊的滯留請求突然到達伺服器。如果只有兩次握手,伺服器會錯誤地認為這是一個新的連接請求並建立連接,造成資源浪費,且可能向一個已關閉的客戶端發送數據。三次握手通過客戶端的第三個ACK確認,確保了伺服器能夠識別並忽略這些失效的連接請求,提高了連接的健壯性。
為何TCP四次揮手不能簡化為三次?TCP連接是全雙工的,即數據可以同時在兩個方向上傳輸。當一方(比如客戶端)發起FIN請求關閉連接時,僅僅表示它已經沒有數據要發送了,但伺服器可能還有未發送完的數據。伺服器接收到FIN后,會先回復一個ACK表示收到關閉請求,然後繼續發送它剩餘的數據。只有當伺服器也發送完所有數據后,才會再次發送FIN報文來關閉自己的發送通道。因此,需要分開兩個步驟(第二次和第三次揮手)來處理,不能合併為一次,以允許伺服器有機會傳輸完剩餘數據。這就是四次揮手的核心原因。
如何理解TIME_WAIT狀態?它有什麼作用?TIME_WAIT狀態是TCP主動關閉連接方在發送完最後一個ACK報文後進入的一種特殊狀態,持續2MSL(最長報文段生存時間)。它的主要作用有兩個:一是確保最後一個ACK報文能夠成功到達被動關閉方。如果ACK丟失,被動關閉方會重發FIN,TIME_WAIT狀態下的主動關閉方可以再次發送ACK。二是防止網路中遲到的舊數據包被新建立的同源同目的連接錯誤接收,造成數據混亂。通過等待2MSL,可以確保所有與舊連接相關的數據包都已在網路中消失。
TCP具有超時重傳機制。如果在握手或揮手過程中某個報文丟失,發送方在設定的超時時間內沒有收到相應的確認報文,它會重傳丟失的報文段。例如,如果客戶端的SYN報文丟失,客戶端會等待一段時間后重發SYN。如果伺服器的SYN+ACK報文丟失,伺服器會重發SYN+ACK。這個機制保證了TCP連接建立和終止的可靠性。
FIN報文和ACK報文是否可以攜帶數據?FIN報文(用於關閉連接)是可以攜帶數據的,但通常情況下它不攜帶數據,只作為控制報文使用。如果FIN報文攜帶著數據,那麼它的序列號會消耗掉,並且會和數據一起被確認。而純ACK報文(不帶SYN或FIN標誌,且不包含應用層數據)本身是不消耗序列號的,也不會攜帶應用層數據,它僅僅用於確認收到的數據。
總結
TCP三次握手和四次揮手是構建和維護互聯網可靠通信的基石。三次握手通過精妙的序列號和確認號機制,確保了客戶端和伺服器都具備發送和接收數據的能力,有效防止了「失效請求」的干擾,從而可靠地建立了連接。而四次揮手則以其分段關閉的特性,優雅地處理了全雙工連接的終止,並藉助TIME_WAIT狀態確保了最終的可靠性以及對未來連接的保護。
深入理解這些底層機制,不僅能幫助我們更好地理解網路應用的行為,也能為我們在面對網路性能問題或故障時提供重要的診斷線索。正是這些看似簡單的報文交換,支撐起了我們今天豐富多彩的數字生活。

