網上關於這個問題吵得很凶,但是仔細看過之后我更偏向認為兩種說的是一樣的。
首先我們來看看 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 的報文……
所以,吵什么吵,今天我們之所以團聚在這里。。。。
