網上關於這個問題吵得很凶,但是仔細看過之後我更偏向認為兩種說的是一樣的。
首先我們來看看 TCP 協議的三次握手過程
如上圖所示:
解釋一下里面的英文:
- 裡面起到作用的一些標誌位就是TCP報文首部裡的內容,ACK確認標誌位,SYN同步標誌位,ack確認號;
- 兩端的狀態CLOSED 就是連線關閉狀態,LISTEN狀態就是監聽狀態,SYN-SENT就是同步已傳送狀態,SYN-RCVD就是同步已接受狀態,ESTABLISHED就是連線已建立狀態。
三報文揮手的過程如下:
- 客戶端傳送連線請求:頭部SYN=1,表明這是一個TCP連線請求報文段,序號seq有一個初始值,作為TCP客戶程式選擇的初始序號。(SYN=1的報文是不能攜帶資料的)
- 伺服器傳送針對收到的連線請求的確認:頭部SYN=1,確認位ACK=1,表明是一個TCP請求確認報文段,seq設定初值y,作為伺服器程式選擇的初始序號,確認號欄位ack=x+1,是對剛才客戶端的x的確認(不能攜帶資料)
- 客戶端傳送針對請求確認的確認:傳送一個普通的TCP確認報文段,進入連線已建立狀態。這個報文的ACK設為1,表明是一個TCP確認報文段,seq=x+1是繼續傳送的序號,確認號欄位ack=y+1是對上一個發出去的y的後續。
隨後,伺服器收到了客戶端的3,那麼就開始進入已建立狀態,通訊開始了。
簡單來說,三個報文分別是,請求-請求確認-請求確認確認(禁止套娃)
一、教材版
原因一:主要是防止客戶端發出的已經失效的連線請求報文段,又傳送到了伺服器,從而導致錯誤,白白浪費資源。
具體情況是,如果只有兩報文握手:
- C發請求,某些原因沒到S;
- C又發,到了S,這個時候因為沒有三握手,兩報文後,建立了正常通訊,完了結束通訊,兩邊連線都關閉了。
- C的第一條請求到了S,S又給了回應,因為是兩握手,S覺得只用等C發請求就可以了,S是established狀態,結果C是closed,白白浪費伺服器資源。
這種說法也來自於《計算機網路的課本》:
“已失效的連線請求報文段” 的產生在這樣一種情況下:client 發出的第一個連線請求報文段並沒有丟失,而是在某個網路結點長時間的滯留了,以致延誤到連線釋放以後的某個時間才到達 server。
本來這是一個早已失效的報文段。但 server 收到此失效的連線請求報文段後,就誤認為是 client 再次發出的一個新的連線請求。於是就向 client 發出確認報文段,同意建立連線。
假設不採用 “三次握手”,那麼只要 server 發出確認,新的連線就建立了。由於現在 client 並沒有發出建立連線的請求,因此不會理睬 server 的確認,也不會向 server 傳送資料。但 server 卻以為新的運輸連線已經建立,並一直等待 client 發來資料。這樣,server 的很多資源就白白浪費掉了。
二、知乎及各論壇討論的另一種
原因二:這種說法來自於對 RFC 的官方文件說法的解讀。
因為TCP 設計中一個基本設定就是,通過TCP 連線傳送的每一個包,都有一個sequence number。而因為每個包都是有序列號的,所以都能被確認收到這些包。確認機制是累計的,所以一個對sequence number X 的確認,意味著 X 序列號之前(不包括 X) 包都是被確認接收到的。
- 結合上面的報文握手的示意圖,也就是說客戶端發出的 seq=X,則 伺服器對 X 的確認是 ack=X+1,就是這個意思。
TCP 協議不限制一個特定的連線(兩端 socket 一樣)被重複使用。所以如果一條連線突然斷開重連後,TCP 怎麼樣識別之前舊連結重發的包?
——這就需要獨一無二的 ISN(初始序列號)機制。那麼這個機制具體實現利用了時鐘blabla生成這個可以認為是獨一無二的 ISN,那麼例子就是:
- A --> B SYN my sequence number is X
- A <-- B ACK your sequence number is X
- A <-- B SYN my sequence number is Y
- A --> B ACK your sequence number is Y
其實對應到上面的三次握手示意圖,也是一樣的東西。最後得出結論:
A three way handshake is necessary because sequence numbers are not tied to a global clock in the network, and TCPs may have different mechanisms for picking the ISN's. The receiver of the first SYN has no way of knowing whether the segment was an old delayed one or not, unless it remembers the last sequence number used on the connection (which is not always possible), and so it must ask the sender to verify this SYN. The three way handshake and the advantages of a clock-driven scheme are discussed in [3].
第一句話翻譯就是,因為 seq 這個東西,並不是和網路中的全域性時鐘繫結的,並且 TCP 協議實現這個初始序列號 ISN 的機制有很多種,所以三次握手是必須的。(?)
第二句話翻譯就是,第一個接收方,假如我們說是伺服器,沒辦法知道這個報文段是不是 old delayed ,除非記住上一次的seq,然而並不總是可能的,所以必須伺服器發給傳送端一個報文去判別這次的報文段。那我們結合上面的這個例子
- A --> B SYN my sequence number is X
- A <-- B ACK your sequence number is X
- A <-- B SYN my sequence number is Y
- A --> B ACK your sequence number is Y
這句話意思就是,伺服器接收了,還要把傳送確認過去,再讓對方確認。
如果沒有第三次握手,也就是說上面的四個步驟就只用省略為 1) 2)3),連線直接建立成功。
發現點什麼了嗎……到這裡的問題和謝希仁老師課本里所講的那種情況其實是一樣的啊,因為沒有第三次握手的確認,導致連線成功了,而這種時候可能接收方收到的確實就是之前 old delayed 的報文……
所以,吵什麼吵,今天我們之所以團聚在這裡。。。。