回答了個(gè)千贊問(wèn)題:TCP為什么需要三次握手?
大家好,我是小林。
之前我在圖解網(wǎng)絡(luò) PDF 里寫(xiě)「TCP 為什么需要三次握手?」,給出了三個(gè)原因:
- 三次握手才可以阻止歷史連接的初始化(主要原因);
- 三次握手才可以同步雙方的初始序列號(hào);
- 三次握手才可以避免資源浪費(fèi);
同時(shí),這個(gè)內(nèi)容也在知乎得到了 1000 多贊。
其中,在講第一個(gè)原因的時(shí)候,提到「三次握手可以通過(guò)上下文判斷當(dāng)前連接是否是歷史連接,而兩次握手無(wú)法判斷」。
因?yàn)楫?dāng)時(shí)沒(méi)有詳細(xì)說(shuō)為什么兩次握手無(wú)法判斷歷史連接,導(dǎo)致有很多讀者私信我這個(gè)問(wèn)題。
所以,這次詳細(xì)說(shuō)一下,順便給大家復(fù)習(xí)下,這個(gè)面試被問(wèn)到發(fā)霉的問(wèn)題。
TCP 兩次握手為什么無(wú)法阻止歷史連接?
我之前的圖解網(wǎng)絡(luò) PDF 里寫(xiě)的是,兩次握手無(wú)法判斷歷史連接。
其實(shí)這句話,不太準(zhǔn)確,因?yàn)榫拖褡x者問(wèn)的那樣,第二次握手的時(shí)候,客戶端也可以根據(jù)他的序列號(hào)和收到的報(bào)文中的確認(rèn)號(hào)進(jìn)行比較。
所以,應(yīng)該改成「TCP 兩次握手無(wú)法阻止歷史連接」。
那為什么 TCP 兩次握手為什么無(wú)法阻止歷史連接呢?
我先直接說(shuō)結(jié)論,主要是因?yàn)樵趦纱挝帐值那闆r下,「被動(dòng)發(fā)起方」沒(méi)有中間狀態(tài)給「主動(dòng)發(fā)起方」來(lái)阻止歷史連接,導(dǎo)致「被動(dòng)發(fā)起方」可能建立一個(gè)歷史連接,造成資源浪費(fèi)。
你想想,兩次握手的情況下,「被動(dòng)發(fā)起方」在收到 SYN 報(bào)文后,就進(jìn)入 ESTABLISHED 狀態(tài),意味著這時(shí)可以給對(duì)方發(fā)送數(shù)據(jù)給,但是「主動(dòng)發(fā)」起方此時(shí)還沒(méi)有進(jìn)入 ESTABLISHED 狀態(tài),假設(shè)這次是歷史連接,主動(dòng)發(fā)起方判斷到此次連接為歷史連接,那么就會(huì)回 RST 報(bào)文來(lái)斷開(kāi)連接,而「被動(dòng)發(fā)起方」在第一次握手的時(shí)候就進(jìn)入 ESTABLISHED 狀態(tài),所以它可以發(fā)送數(shù)據(jù)的,但是它并不知道這個(gè)是歷史連接,它只有在收到 RST 報(bào)文后,才會(huì)斷開(kāi)連接。
可以看到,上面這種場(chǎng)景下,「被動(dòng)發(fā)起方」在向「主動(dòng)發(fā)起方」發(fā)送數(shù)據(jù)前,并沒(méi)有阻止掉歷史連接,導(dǎo)致「被動(dòng)發(fā)起方」建立了一個(gè)歷史連接,又白白發(fā)送了數(shù)據(jù),妥妥地浪費(fèi)了「被動(dòng)發(fā)起方」的資源。
因此,要解決這種現(xiàn)象,最好就是在「被動(dòng)發(fā)起方」發(fā)送數(shù)據(jù)前,也就是建立連接之前,要阻止掉歷史連接,這樣就不會(huì)造成資源浪費(fèi),而要實(shí)現(xiàn)這個(gè)功能,就需要三次握手。
三次握手阻止歷史連接的過(guò)程如下圖,注意圖中的兩個(gè)連接的序列號(hào)是不一樣的,因此新舊 SYN 報(bào)文并不是發(fā)生了超時(shí)重傳,兩個(gè)都是獨(dú)立的連接。
客戶端連續(xù)發(fā)送多次 SYN 建立連接的報(bào)文,在網(wǎng)絡(luò)擁堵情況下:
- 一個(gè)「舊 SYN 報(bào)文」比「最新的 SYN 」 報(bào)文早到達(dá)了服務(wù)端;
- 那么此時(shí)服務(wù)端就會(huì)回一個(gè) SYN + ACK 報(bào)文給客戶端;
- 客戶端收到后可以根據(jù)自身的上下文,判斷這是一個(gè)歷史連接(序列號(hào)過(guò)期),那么客戶端就會(huì)發(fā)送 RST 報(bào)文給服務(wù)端,表示中止這一次連接。
可以看到,在三次握手的情況下, 可以在服務(wù)端建立連接之前,可以阻止掉了歷史連接,從而保證建立的連接不是歷史連接。
怎么樣,是不是稍微圖解下,就明明白白了!