TCP三次握手原理
本文主要內容
- TCP資料包格式
- 三次握手原理
- TCP的傳輸和確認
- TCP的序號和確認序號
1、TCP資料包格式
TCP資料包格式如下:

- 埠號,用於區分發送訊息或者接收訊息的程序。
- 序號,首位元組在整個資料流中的位置。初始序列號隨機產生,並在連線建立階段予以同步。
- 確認序號,表示序號為確認號減去1的資料包及其以前的所有資料包已經正確接收,也就是說他相當於下一個準備接收的位元組的序號
注意到中間還有幾個標誌位:
- URG—為1表示高優先順序資料包,緊急指標欄位有效。
- ACK—為1表示確認號欄位有效
- PSH—為1表示是帶有PUSH標誌的資料,指示接收方應該儘快將這個報文段交給應用層而不用等待緩衝區裝滿。
- RST—為1表示出現嚴重差錯。可能需要重現建立TCP連線。還可以用於拒絕非法的報文段和拒絕連線請求。
- SYN—為1表示這是連線請求或是連線接受請求,用於建立連線和使順序號同步
- FIN—為1表示傳送方沒有資料要傳輸了,要求釋放連線。
資料包格式當中,最重要的是理解序號和確認序號。TCP為什麼是穩定可靠的,與序號與確認序號這套機制緊密相關,這也是TCP的精髓。
2、TCP的三次握手

眾所周知,TCP協議是可靠的,而UDP協議是不可靠的。在一些場景中必須用TCP,比如說使用者登入,必須給出明確答覆是否登入成功等。而有些場景中,使用者是否接收到資料則不那麼關鍵,比如網路遊戲當中,玩家射出一顆子彈,另外的玩家是否看到,完全取決於當前網路環境,如果網路卡頓,就會有玩家已經被射殺,但介面仍然重新整理不出來的情況。這種情形適合UDP。
為了保證TCP協議可靠,在建立連線之時就要得到保證。
最初兩端的TCP程序都處於CLOSED關閉狀態,A主動開啟連線,而B被動開啟連線。(A、B關閉狀態CLOSED——B收聽狀態LISTEN——A同步已傳送狀態SYN-SENT——B同步收到狀態SYN-RCVD——A、B連線已建立狀態ESTABLISHED)
B伺服器程序就處於LISTEN(收聽)狀態,等待客戶的連線請求。若有,則作出響應。
- 第一次握手:A客戶程序向B發出連線請求報文段,(首部的同步位SYN=1,初始序號seq=x),(SYN=1的報文段不能攜帶資料)但要消耗掉一個序號,此時TCP客戶程序進入SYN-SENT(同步已傳送)狀態。
- 第二次握手:B收到連線請求報文段後,如同意建立連線,則向A傳送確認,在確認報文段中(SYN=1,ACK=1,確認號ack=x+1,初始序號seq=y),TCP伺服器程序進入SYN-RCVD(同步收到)狀態;
- 第三次握手:TCP客戶程序收到B的確認後,要向B給出確認報文段(ACK=1,確認號ack=y+1,序號seq=x+1)(初始為seq=x,第二個報文段所以要+1),ACK報文段可以攜帶資料,不攜帶資料則不消耗序號。TCP連線已經建立,A進入ESTABLISHED(已建立連線)。
當B收到A的確認後,也進入ESTABLISHED狀態。
3、TCP的傳輸和確認
TCP 傳輸的可靠性,可以用一句話歸結:每收到對方資料,就傳送 ACK 進行確定,傳送方傳送後沒有收到 ACK 就隔一段時間重發。
就是 A 向 B 傳送訊息(下面將 TCP 的報文直接看做是訊息,訊息一詞跟 TCP 報文混用),B 收到訊息後需要向 A 傳送 ACK。這個 ACK 相當於返回結果,沒有返回結果,A 就重新發送訊息。
歸納起來,A 有 3 種訊息需要確認。
- SYN,用於建立連線。
- FIN,用於終止連線。
- 傳送資料。
另外 A 也可以傳送 RST 訊息,代表出錯了。出錯訊息不需要確認。RST 也可以當成返回介面,替代正常的 ACK。返回 ACK,表示訊息傳送並處理成功,返回 RST 表示訊息處理失敗。因為通過網路傳輸,還有第三種結果,就是不確定成功失敗。這樣歸納起來。就有三種返回結果。
- ACK,成功。繼續進行下一步。
- RST,出錯。終止連線。
- 不確定,重發。
其中第三種情況又有兩種具體情況。,
A 向 B 傳送訊息,但 B 根本沒有收到。
B 收到訊息後,傳送 ACK,但 A 沒有收到。
這兩種具體情況,A 根本識別不了,都只能重發。
4、TCP的序號和確認序號
A 向 B 傳送訊息,假如同時傳送 a、b、c、d 訊息,因為通過網路,這些訊息的順序並非固定的。而 B 返回 ACK 結果,這樣就有一個問題,這個結果到底對應了哪個訊息?另外當 A 超時重發後,原來的訊息延時一段時候,又重新到達了 B,這樣 B 就收到兩條相同的訊息,那麼 B 怎麼確定這兩條訊息是相同的呢?
為了解決這個對應問題,每一條訊息都需要有一個編號,返回結果也應該有一個編號。TCP 的序號可以看成是傳送訊息的編號,確認序號可以看成是返回結果的編號。有了編號,重複的訊息才可以忽略,返回結果(ACK)才可以跟訊息對應起來。
當建立連線的時候,TCP 選定一個初始序號,之後每傳送一個數據包(訊息),就將序號遞增,保證每傳送不同的資料包,資料包的序號都是不同的。TCP 是這樣處理的:
- 傳送 SYN, 分配當前序號,當前序號遞增 1。
- 傳送 FIN, 分配當前序號,當前序號遞增 1。
- 傳送資料,分配當前序號,當前序號遞增資料的位元組長度。
SYN、FIN 也需要遞增序號。不然 A 向 B 重發多個 SYN 或者 FIN, B 根本判斷不了 SYN 是否相同,這樣就不可以忽略重複的資料包了。
當 TCP 傳送 ACK 時,相當於返回結果,需要帶有確認序號,以便跟傳送的訊息對應起來。
當傳送包編號為 a,遞增長度為 len。其中 SYN 和 FIN 可以看成是遞增長度為 1。這條訊息可以這樣表示為:
- msg[a, a + len)
現在來回顧三次握手過程。 A
傳送序列號x給 B
, B
回覆 A
確認號 x+ 1,同時傳送序列號 y, A
接收到 B
的回覆後,再回復確認號 y+1,同時傳送序列號 x+1。給對方的回覆一定是接收到的序號加1,這樣對方才能知道我已經收到了,這樣才能保證TCP是可靠的。