一、TCP頭格式組成
為了使你更好的理解 TCP 三次握手和四次揮手過程,本小節先介紹下 TCP 頭部格式。
(1) 來源連接埠號碼和目的連接埠號碼:代表連線發起方和連線接收方
(2) 序號:在建立連線時,由電腦生產的隨機數作為初始值,透過SYN包傳給接收端主機,每發送一次數據,就累積一次該數據位元組數的大小。用來解決網路包亂序問題。
(3) 確認序號:指下一次期望收到的數據的序號,發送端收到這個確認應答以後,可以認為在這個序號以前的數據,都已經被正常接收。 用來解決網路丟包的問題
(4) 標誌位,如上圖,共6個
URG
ACK:當位元為 1 時,「確認應答」的欄位變為有效,TCP 規定除了最初建立連線時的 SYN 套件之外該位元必須設定為 1
PSH
RST:此位元為 1 時,表示 TCP 連線中出現異常必須強制斷開連線。
SYN:當位元為 1 時,表示希望建立連接,並在其「序號」的欄位進行序號初始值的設定。
FIN:該位元為 1 時,表示今後不會再有資料發送,希望斷開連線。當通訊結束希望斷開連線時,通訊雙方的主機之間就可以相互交換 FIN 位元為 1 的 TCP 段。
(5) 數據:連線需要發送的內容。
二、建立連線:三次握手
三次握手(Three-way Handshake)是 TCP 協定中用來建立連線的一個重要環節。在這過程中,客戶端和伺服器需要互相傳送三個資料包,以確保雙方的接收和傳送能力均正常,並為後續的資料傳輸指定初始化序號,從而確保資料傳輸的可靠性。
TCP 三次握手流程圖如下所示:
圖中字符詳解:
SYN:代表連線請求或接收的封包段。
seq:指傳送的第一個位元組的序號。
ACK:確認封包文段,用於回應 SYN。
ack:確認號,表示希望收到的下一個資料的第一個位元組的序號。
在 TCP 協定中,主動發起連線請求的一方稱為客戶端,而被動等待連線的一方則稱為服務端。無論是客戶端或服務端,一旦 TCP 連線成功建立,雙方都能進行資料的傳送與接收。
連線建立之初,伺服器和用戶端都處於 CLOSED 狀態。在通訊正式開始前,雙方需要分別建立自己的傳輸控制塊(TCB)。伺服器完成 TCB 建立後,會進入 LISTEN 狀態,隨時準備接收客戶端發送的連線請求。
1. 第一次握手
客戶端向服務端發送一個 SYN 封包(SYN=1),並指明客戶端的初始化序號 ISN(x),即圖中的 seq=x,它表示本封包所傳送的資料的第一個位元組的序號。在發送 SYN 封包後,客戶端進入 SYN_SENT 狀態,表示它正在等待服務端的連線確認。
SYN_SENT 狀態解釋:當客戶端發送連線請求後,它進入 SYN_SENT 狀態,等待服務端的回應。在這個狀態下,客戶端準備好了接受服務端的連線確認。
TCP 協定規定:SYN=1 的封包是用於建立連線的請求,它不攜帶任何數據,但會消耗一個序號。這是 TCP 協定確保連線建立過程中的有序性和可靠性的一種方式。
2. 第二次握手
伺服器接收到客戶端的 SYN 封包後,會以 SYN 封包作為回應(SYN=1),並賦予自己獨特的初始化序號ISN(y),即圖中的 seq=y。同時,伺服器將客戶端的 ISN+1 設定為確認號 ack 的值,以此確認已收到客戶端的 SYN 封包,並期待接收到的下一個資料封包的起始序號為 x+1。在此之後,伺服器會進入 SYN-RCVD 狀態,等待連線請求的進一步確認。
SYN-RCVD 狀態解析:當伺服器在收到並傳送連線請求後,會進入 SYN-RCVD 狀態,此時它正在等待初始連線請求的確認。在這個狀態下,伺服器已經準備好接受來自客戶端的進一步通訊。
TCP 協定規定:SYN=1 且 ACK=1 的封包是用於確認連線的應答,它同樣不攜帶任何數據,但透過確認號的使用,確保了連線建立過程中的有序性和可靠性。
3. 第三次握手
在收到伺服器發送的 SYN 封包後,用戶端會回應一個 ACK 封包。這個 ACK 封包將伺服器的 ISN+1 作為 ack 的值,表示用戶端已經收到了伺服器的 SYN 封包,並期待接收到的下一個資料封包的起始序號為 y+1。
同時,客戶端將自己的序號 seq 設定為 x+1,即初始序號 seq=x 增加 1。完成這些操作後,用戶端進入 ESTABLISHED 狀態,表示連線已成功建立。伺服器收到這個 ACK 封包後,也會轉入 ESTABLISHED 狀態,此時雙方連線的建立工作已全部完成。
ESTABLISHED 狀態解釋:當一個 TCP 連線進入 ESTABLISHED 狀態時,它表示連線已經打開,資料可以開始在雙方之間傳送。
三、斷開連結:四次揮手
TCP 連線的終止需要經過四次包的交換,因此被稱為四次揮手。在這四次交換中,客戶端或伺服器都可以主動發起連線的釋放動作。值得注意的是,TCP 連接是雙向的,因此四次揮手中,前兩次主要用於斷開一個方向的連接,後兩次則用於斷開另一個方向的連接。
1. 第一次揮手
客戶端首先發送一個 FIN 封包,其中包含一個序號 seq=u,表示請求連線終止。在發送完畢後,客戶端停止資料發送,並主動關閉 TCP 連線。此時,客戶端進入 FIN_WAIT_1 狀態,等待伺服器的確認。
FIN_WAIT_1 狀態解析:此狀態表示客戶端正在等待遠端 TCP 的連線中斷要求,或等待先前連線中斷要求的確認。 FIN=1 標誌著該封包段是一個連線釋放請求。而 seq=u 則代表客戶端向伺服器發送的最後一個位元組的序號。
2. 第二次揮手
服務端在收到客戶端的 FIN 封包後,會傳送一個 ACK 封包作為回應。這個 ACK 封包中,序號值設為客戶端序號值加 1,意圖確認已收到客戶端的封包。隨後,服務端進入 CLOSE_WAIT 狀態,等待本地用戶的連線中斷請求。
CLOSE_WAIT 狀態解析:在此狀態下,服務端等待來自本機使用者的連線釋放請求。 ACK 封包中的 ACK=1 表示應答,而 seq=v 則指明了服務端釋放應答報文段的首字節序號。同時,ack=u+1 表示服務端希望從第 u+1 個位元組開始接收封包段,並已成功接收了前 u 個位元組。
完成第二次揮手後,客戶端到服務端的連線已釋放,服務端不再接收客戶端數據,而客戶端也已無數據待發送。然而,服務端到客戶端的連線仍保持開啟,若服務端在此期間發送數據,客戶端仍需正常接收。此狀態將持續一段時間,直到整個 CLOSE-WAIT 狀態結束。
3. 第三次揮手
服務端在完成資料的發送後,會傳送一個連線釋放封包給客戶端。這個報文頭包含 FIN 標誌位元為 1,以及 ack 序號值為 u+1。由於在 CLOSE_WAIT 狀態期間,服務端可能又發送了一些數據,假設此時的序號為 seq=w。傳送完畢後,服務端進入 LAST_ACK 狀態,等待來自客戶端的連線中斷確認。
4. 第四次揮手
用戶端收到服務端的 FIN 封包後,會回應一個 ACK 封包,其中 ack 序號值為 w+1,同時將自己的序號加 1為 ACK 封包的 seq 序號值,即 seq=u+1。此後,客戶端進入 TIME_WAIT 狀態。
TIME_WAIT:確保遠端 TCP 收到連線中斷要求的確認狀態會持續 2MSL(最長封包壽命)的時間。在此期間, TCP 連線並未完全釋放。若在這段時間內未收到服務端的重發請求,用戶端將進入 CLOSED 狀態,並撤銷 TCB。
服務端在收到客戶端的確認 ACK 封包後,會立即進入 CLOSED 狀態,並撤銷 TCB,從而結束此次 TCP 連線。值得注意的是,服務端結束 TCP 連線的時間點通常早於客戶端。