大家好,我是小林。
之前我在圖解網絡 PDF 里寫「TCP 為什么需要三次握手?」,給出了三個原因:
- 三次握手才可以阻止歷史連接的初始化(主要原因);
- 三次握手才可以同步雙方的初始序列號;
- 三次握手才可以避免資源浪費;
同時,這個內容也在知乎得到了 1000 多贊。
其中,在講第一個原因的時候,提到「三次握手可以通過上下文判斷當前連接是否是歷史連接,而兩次握手無法判斷」。
因為當時沒有詳細說為什么兩次握手無法判斷歷史連接,導致有很多讀者私信我這個問題。
所以,這次詳細說一下,順便給大家復習下,這個面試被問到發霉的問題。
TCP 兩次握手為什么無法阻止歷史連接?
我之前的圖解網絡 PDF 里寫的是,兩次握手無法判斷歷史連接。
其實這句話,不太準確,因為就像讀者問的那樣,第二次握手的時候,客戶端也可以根據他的序列號和收到的報文中的確認號進行比較。
所以,應該改成「TCP 兩次握手無法阻止歷史連接」。
那為什么 TCP 兩次握手為什么無法阻止歷史連接呢?
我先直接說結論,主要是因為在兩次握手的情況下,「被動發起方」沒有中間狀態給「主動發起方」來阻止歷史連接,導致「被動發起方」可能建立一個歷史連接,造成資源浪費。
你想想,兩次握手的情況下,「被動發起方」在收到 SYN 報文后,就進入 ESTABLISHED 狀態,意味著這時可以給對方發送數據給,但是「主動發」起方此時還沒有進入 ESTABLISHED 狀態,假設這次是歷史連接,主動發起方判斷到此次連接為歷史連接,那么就會回 RST 報文來斷開連接,而「被動發起方」在第一次握手的時候就進入 ESTABLISHED 狀態,所以它可以發送數據的,但是它并不知道這個是歷史連接,它只有在收到 RST 報文后,才會斷開連接。
可以看到,上面這種場景下,「被動發起方」在向「主動發起方」發送數據前,并沒有阻止掉歷史連接,導致「被動發起方」建立了一個歷史連接,又白白發送了數據,妥妥地浪費了「被動發起方」的資源。
因此,要解決這種現象,最好就是在「被動發起方」發送數據前,也就是建立連接之前,要阻止掉歷史連接,這樣就不會造成資源浪費,而要實現這個功能,就需要三次握手。
三次握手阻止歷史連接的過程如下圖,注意圖中的兩個連接的序列號是不一樣的,因此新舊 SYN 報文并不是發生了超時重傳,兩個都是獨立的連接。
客戶端連續發送多次 SYN 建立連接的報文,在網絡擁堵情況下:
- 一個「舊 SYN 報文」比「最新的 SYN 」 報文早到達了服務端;
- 那么此時服務端就會回一個 SYN + ACK 報文給客戶端;
- 客戶端收到后可以根據自身的上下文,判斷這是一個歷史連接(序列號過期),那么客戶端就會發送 RST 報文給服務端,表示中止這一次連接。
可以看到,在三次握手的情況下, 可以在服務端建立連接之前,可以阻止掉了歷史連接,從而保證建立的連接不是歷史連接。
怎么樣,是不是稍微圖解下,就明明白白了!
原文鏈接:https://mp.weixin.qq.com/s?__biz=MzUxODAzNDg4NQ==&mid=2247501989&idx=1&sn=a77db1ccf6387370aab9aca4541f4536&chksm=f98d8c0fcefa051908ed287ac899fb7afe4819f36b62facf1cc2e8daf01a8c5ed5588d77f562&mpshare=1&s