TCP 為什麼三次握手而不是兩次握手(正解版)
參考文章
大部分網路部落格的錯誤解讀
首先需要宣告的是, 百度搜索到的大部分網路部落格關於這個問題的解答都是不清晰或者不準確的。 討論這個問題的大部分部落格都會引用《計算機網路》的內容:
- 防止已失效的連線請求又傳送到伺服器端,因而產生錯誤
不幸的是, 這種解釋是不準確的, TCP 採用三次握手的原因其實非常簡單, 遠沒有大部分部落格所描述的那樣雲山霧繞。
這裡先給出結論:
- 為了實現可靠資料傳輸, TCP 協議的通訊雙方, 都必須維護一個序列號, 以標識傳送出去的資料包中, 哪些是已經被對方收到的。 三次握手的過程即是通訊雙方相互告知序列號起始值, 並確認對方已經收到了序列號起始值的必經步驟
- 如果只是兩次握手, 至多隻有連線發起方的起始序列號能被確認, 另一方選擇的序列號則得不到確認
先修知識
TCP 通訊流程
TCP 的通訊流程
上圖中的每一個箭頭都代表著一次 TCP資料包的傳送
- 需要注意的是, 上圖中出現的 ACK = x +1 的寫法很容易讓人誤以為資料包中的 ACK 域的資料值被填成了 y+1 。 ACK = x+1 的實際含義是:
- TCP 包的 ACK 標誌位(1 bit) 被置成了 1
- TCP 包的確認號(acknowledgement number ) 的值為 x+1
- 類似的, TCP 資料包中的 SYN 標誌位, 也容易與序號(sequence number) 混淆, 這點需要讀者注意
TCP 資料包結構圖
為什麼 TCP 需要握手這個操作
在解答為什麼 TCP 需要三次握手, 而不是兩次之前, 首先需要回答的問題是:
- 為什麼需要握手這個操作, 能不能不握手?
如果讀者對比一下 UDP 的通訊流程和 TCP 的通訊流程, 可以發現, 在 UDP 協議中, 是沒有握手這個操作的。
這裡就引出了 TCP 與 UDP 的一個基本區別, TCP 是可靠通訊協議, 而 UDP 是不可靠通訊協議。
- TCP 的可靠性含義: 接收方收到的資料是完整, 有序, 無差錯的。
- UDP 不可靠性含義: 接收方接收到的資料可能存在部分丟失, 順序也不一定能保證。
UDP 和 TCP 協議都是基於同樣的網際網路基礎設施, 且都基於 IP 協議實現, 網際網路基礎設施中對於資料包的傳送過程是會發生丟包現象的, 為什麼 TCP 就可以實現可靠傳輸, 而 UDP 不行?
TCP 協議為了實現可靠傳輸, 通訊雙方需要判斷自己已經發送的資料包是否都被接收方收到, 如果沒收到, 就需要重發。 為了實現這個需求, 很自然地就會引出序號(sequence number) 和 確認號(acknowledgement number) 的使用。
傳送方在傳送資料包(假設大小為 10 byte)時, 同時送上一個序號( 假設為 500),那麼接收方收到這個資料包以後, 就可以回覆一個確認號(510 = 500 + 10) 告訴傳送方 “我已經收到了你的資料包, 你可以傳送下一個資料包, 序號從 510 開始” 。
這樣傳送方就可以知道哪些資料被接收到,哪些資料沒被接收到, 需要重發。
為什麼需要三次握手,而非兩次
正如上文所描述的,為了實現可靠傳輸,傳送方和接收方始終需要同步( SYNchronize )序號。 需要注意的是, 序號並不是從 0 開始的, 而是由傳送方隨機選擇的初始序列號 ( Initial Sequence Number, ISN )開始 。 由於 TCP 是一個雙向通訊協議, 通訊雙方都有能力傳送資訊, 並接收響應。 因此, 通訊雙方都需要隨機產生一個初始的序列號, 並且把這個起始值告訴對方。
於是, 這個過程就變成了下面這樣。
下面這個流程圖描述的和上面一樣, 但是更加清楚的展示了 TCP 資料包標誌位, 以及資料域的命名來源。