1. 程式人生 > >tcp為什麼要三次握手,而不能二次握手?

tcp為什麼要三次握手,而不能二次握手?

http://bbs.csdn.net/topics/390706512?page=1

謝希仁版《計算機網路》中的例子是這樣的,“已失效的連線請求報文段”的產生在這樣一種情況下:client發出的第一個連線請求報文段並沒有丟失,而是在某個網路結點長時間的滯留了,以致延誤到連線釋放以後的某個時間才到達server。本來這是一個早已失效的報文段。但server收到此失效的連線請求報文段後,就誤認為是client再次發出的一個新的連線請求。於是就向client發出確認報文段,同意建立連線。假設不採用“三次握手”,那麼只要server發出確認,新的連線就建立了。由於現在client並沒有發出建立連線的請求,因此不會理睬server的確認,也不會向server傳送ack包。但server卻以為新的運輸連線已經建立,並一直等待client發來資料。這樣,server的很多資源就白白浪費掉了。採用“三次握手”的辦法可以防止上述現象發生。例如剛才那種情況,client不會向server的確認發出確認。server由於收不到確認,就知道client並沒有要求建立連線。



在謝希仁著《計算機網路》第四版中講“三次握手”的目的是“為了防止已失效的連線請求報文段突然又傳送到了服務端,因而產生錯誤”。在另一部經典的《計算機網路》(Andrew S.Tanenbaum著,第四版)一書中講“三次握手”的目的是為了解決“網路中存在延遲的重複分組”的問題。這兩種不用的表述其實闡明的是同一個問題。

   校評:為什麼紅線處說client不會理睬server的確認,不會向server傳送資料,這個需要解釋一下,我們知道客戶端在呼叫connect函式之後進入了SYN_SEND狀態,只有接收到伺服器端的SYN+ACK包才進入ESTABLISHED狀態。因為對於已經失效的連線請求報文,由於此時客戶端沒有進入SYN_SEND狀態,而處於CLOSED狀態,即使收到伺服器端的SYN+ACK包,也不會產生任何狀態變化,也就不會理踩server的確認和傳送ack包了。



  注意:上面的解釋僅僅是假設客戶端處於CLOSED狀態時廢棄包的到來,並沒有對客戶端處於非CLOSED狀態時廢棄包的到來進行分析,好歹通過google,得到了非CLOSED狀態下為什麼兩次握手可能會出現的問題,這裡也分兩種情況,一種是廢棄的報文的干擾,一種是廢棄的SYN報文的干擾。





附華中科技大學有一題研究生入學考題,是下面題目的中文翻譯版(不過我覺得這個答案有點牽強,畢竟現在tcp傳輸機制中都有定時器,會有超時重傳,不會導致死鎖的,當然如果沒有超時機制,死鎖還是可能的):

Imagine that a two-way handshake rather than a three-way handshake were used to set up connections. In other words, the third message was not required. Are deadlocks now possible? Give an example or show that none exist.


Answer:
Deadlocks are possible. For example, a packet arrives at A out of the blue, and A acknowledges it. The acknowledgement gets lost, but A is now open while B knows nothing at all about what has happened. Now the same thing happens to B, and both are open, but expecting different sequence numbers. Timeouts have to be introduced to avoid the deadlocks.


網上有一段流傳很廣的解釋:

 為什麼不能用兩次握手進行連線?

我們知道,3次握手完成兩個重要的功能,既要雙方做好傳送資料的準備工作(雙方都知道彼此已準備好),也要允許雙方就初始序列號進行協商,這個序列號在握手過程中被髮送和確認。
    現在把三次握手改成僅需要兩次握手,死鎖是可能發生的。作為例子,考慮計算機S和C之間的通訊,假定C給S傳送一個連線請求分組,S收到了這個分組,併發 送了確認應答分組。按照兩次握手的協定,S認為連線已經成功地建立了,可以開始傳送資料分組。可是,C在S的應答分組在傳輸中被丟失的情況下,將不知道S 是否已準備好,不知道S建立什麼樣的序列號,C甚至懷疑S是否收到自己的連線請求分組。在這種情況下,C認為連線還未建立成功,將忽略S發來的任何資料分 組,只等待連線確認應答分組。而S在發出的分組超時後,重複傳送同樣的分組。這樣就形成了死鎖。


校評:這個解釋也值得商榷,這裡指說S超時重傳,難道C沒有收到S的ACK訊號,不會重新發送SYN訊號麼? 只要重新發送SYN,S端自然也會發送確認應答分組,這樣就不會導致死鎖。