轉(zhuǎn)自連接地址
TCP協(xié)議是我們幾乎每天都會(huì)接觸到的網(wǎng)絡(luò)協(xié)議,絕大多數(shù)網(wǎng)絡(luò)協(xié)議的協(xié)議都是基于TCP協(xié)議的蒂秘,學(xué)過計(jì)算機(jī)網(wǎng)絡(luò)或者對(duì)TCP協(xié)議稍有了解的人都知道——使用TCP協(xié)議簡歷鏈接需要經(jīng)過三次握手(three-way handshake)。
如果讓我們簡單說說TCP建立連接的過程,相信很多準(zhǔn)備過面試的人都會(huì)非常了解,但是一旦想要深究「為什么TCP建立連接需要三次握手知给?」,作者相信大多數(shù)人都沒有辦法回答這個(gè)問題或者給出錯(cuò)誤的答案描姚,這篇文章就會(huì)討論為什么我們需要三次握手才能建立TCP連接涩赢。
需要注意的是我們會(huì)將重點(diǎn)放到為什么TCP建立需要「三次握手」,而不僅僅是為什么需要「三次」握手
概述
在具體分析今天的問題之前轩勘,我們首先可以了解一下最常見的錯(cuò)誤類比筒扒,這個(gè)對(duì)TCP鏈接過程的錯(cuò)誤比喻誤導(dǎo)了很多人,作者在比較長的一段時(shí)間內(nèi)也認(rèn)為它能夠很好地描述TCP建立連接為什么需要三次握手:
- 你能聽得到嗎绊寻?
- 我能聽到花墩,你能聽到?
- 我也能聽到澄步。
這種類比來解釋問題往往就會(huì)面臨「十個(gè)類比九個(gè)錯(cuò)」的尷尬局面冰蘑,如果別人用類比回答你的為什么,你需要仔細(xì)想一想他的類比里究竟哪里有漏洞村缸;類比帶來的解釋往往只能有片面的相似性祠肥,我們永遠(yuǎn)也無法找到?jīng)Q定正確的類比,它只在我們想要通俗易懂地展示事務(wù)的特性時(shí)才能發(fā)揮較大的作用梯皿,我們?cè)谖恼碌暮竺鏁?huì)介紹為什么這里的類比有問題仇箱,各位讀者也可以帶著疑問來閱讀剩下的內(nèi)容。
很多人嘗試回答或者思考這個(gè)問題的時(shí)候其實(shí)關(guān)注點(diǎn)都放在三次握手中的三次上面东羹,這確實(shí)很重要剂桥,但是如果重新審視這個(gè)問題,我們對(duì)于「什么是連接」真的清楚属提?只有知道鏈接的定義权逗,我們才能去嘗試回答為什么TCP連接需要三次握手。
The reliability and flow control mechanisms described above require that TCPs initialize and maintain certain status information for each data stream. The combination of this information, including sockets, sequence numbers, and window sizes, is called a connection.
RFC 793 - Transmission Control Protocol 文檔中非常清楚地定義了TCP中的連接是什么,我們簡單總結(jié)一下:用于保證可靠性和流控制機(jī)制的信息斟薇,包括Socket火惊、序列號(hào)以及窗口大小叫做連接。
所以奔垦,建立TCP連接就是通信的雙方需要對(duì)上述的三種信息達(dá)成共識(shí),連接中的一對(duì)Socket是由互聯(lián)網(wǎng)地址標(biāo)志符合端口組成的尸疆,窗口大小主要做流控制椿猎,最后的序列號(hào)是用來追蹤通信發(fā)起方發(fā)送的數(shù)據(jù)包序號(hào),接收方可以通過序列號(hào)向發(fā)送方確認(rèn)某個(gè)數(shù)據(jù)包的成功接收寿弱。
到這里犯眠,我們將原有的問題轉(zhuǎn)換成了「為什么需要通過三次握手才可以初始化Sockets、窗口大小和初始序列號(hào)症革?」筐咧,那么接下來我們就開始對(duì)這個(gè)細(xì)化的問題進(jìn)行分析并尋找解釋。
設(shè)計(jì)
這篇文章主要會(huì)從以下幾個(gè)方面介紹為什么我們需要通過三次握手才可以初始化Sockets噪矛、窗口大小量蕊、初始化序列號(hào)并建立TCP連接:
- 通過三次握手才能阻止重復(fù)歷史連接的初始化;
- 通過三次握手才能對(duì)通信雙方的初始序列號(hào)進(jìn)行初始化艇挨;
- 討論其他次數(shù)握手建立的可能性残炮;
這幾個(gè)論點(diǎn)中的第一個(gè)是TCP選擇使用三次握手的最主要原因,其他的幾個(gè)原因相比之下都是次要的原因缩滨,我們?cè)谶@里對(duì)他們的討論只是為了讓整個(gè)視角更加豐富势就,通過多方面理解這一有趣的設(shè)計(jì)決策
歷史連接
RFC 793 - Transmission Control Protocol 其實(shí)就指出了TCP連接使用三次握手的首要原因——為了阻止歷史的重復(fù)連接初始化造成的混亂問題,防止使用TCP協(xié)議通信的雙方建立了錯(cuò)誤的連接脉漏。
The principle reason for the three-way handshake is to prevent old duplicate connection initiations from causing confusion.
想象一下這個(gè)場景苞冯,如果通信雙方的通信次數(shù)只有兩次,那么發(fā)送方一旦發(fā)出建立連接的請(qǐng)求之后它就沒有辦法撤回這一次請(qǐng)求侧巨,如果在網(wǎng)絡(luò)狀況復(fù)雜或者較差的網(wǎng)絡(luò)中舅锄,發(fā)送方連續(xù)發(fā)送多次建立連接的請(qǐng)求,如果TCP建立連接只能通信兩次刃泡,那么接收方只能選擇接受或者拒絕發(fā)送方發(fā)起的請(qǐng)求巧娱,它并不清楚這一次請(qǐng)求是不是由于網(wǎng)絡(luò)擁堵而早早過期的連接。
所以烘贴,TCP選擇三次握手來建立連接并在連接引入了RST
這一控制消息禁添,接收方當(dāng)收到請(qǐng)求時(shí)會(huì)將發(fā)送方發(fā)來的SEQ+1
發(fā)送回接收方,這時(shí)由發(fā)送發(fā)來判斷當(dāng)前連接是否是歷史連接:
- 如果當(dāng)前連接是歷史連接桨踪,即
SEQ
過期或者超時(shí)老翘,那么發(fā)送方會(huì)直接發(fā)送RST
控制消息中止這一次連接; - 如果是當(dāng)前連接不是歷史連接,那么發(fā)送方就會(huì)發(fā)送
ACK
控制消息铺峭,通信雙方就會(huì)成功建立連接墓怀;
使用三次握手和RST
控制消息將是否建立連接的最終控制權(quán)交給了發(fā)送方,因?yàn)橹挥邪l(fā)送方有足夠的上下文來判斷當(dāng)前連接是否是錯(cuò)誤的或者過期的卫键,這也是TCP使用三次握手建立連接的最主要原因傀履。
初始序列號(hào)
另一個(gè)使用三次握手的重要的原因就是通信雙方都需要獲得一個(gè)用于發(fā)送信息的初始化序列號(hào),作為一個(gè)可靠的傳輸層協(xié)議莉炉,TCP需要在不穩(wěn)定的網(wǎng)絡(luò)環(huán)境中構(gòu)建一個(gè)可靠的傳輸層钓账,網(wǎng)絡(luò)的不確定性可能會(huì)導(dǎo)致數(shù)據(jù)包的缺失和順序顛倒等問題,常見的問題可能包括:
- 數(shù)據(jù)包被發(fā)送方多次發(fā)送造成數(shù)據(jù)的重復(fù)絮宁;
- 數(shù)據(jù)包在傳輸?shù)倪^程中被路由或者其他節(jié)點(diǎn)丟失梆暮;
- 數(shù)據(jù)包達(dá)到接收方可能無法按照發(fā)送順序;
為了解決上述這些可能存在的問題绍昂,TCP協(xié)議要求發(fā)送方在數(shù)據(jù)包中加入「序列號(hào)」字段啦粹,有了數(shù)據(jù)包對(duì)應(yīng)的序列號(hào),我們就可以:
- 接收方可以通過序列號(hào)對(duì)重復(fù)的數(shù)據(jù)包進(jìn)行去重窘游;
- 發(fā)送方會(huì)在對(duì)應(yīng)數(shù)據(jù)包未被ACK時(shí)進(jìn)行重復(fù)發(fā)送唠椭;
- 接收方可以根據(jù)數(shù)據(jù)包的序列號(hào)對(duì)它們進(jìn)行重新排序;
序列號(hào)在TCP連接中有著非常重要的作用忍饰,初始序列號(hào)作為TCP連接的一部分也需要在三次我收期間進(jìn)行初始化泪蔫,由于TCP連接通信的雙方都需要獲得初始序列號(hào),所以它們其實(shí)需要向雙方發(fā)送SYN
控制消息并攜帶自己期望的初始化序列號(hào)SEQ
喘批,對(duì)方在接受到SYN
消息之后會(huì)通過ACK
控制消息以及SEQ+1
來進(jìn)行確認(rèn)撩荣。
如上圖所示,通信雙方的兩個(gè)
TCP A/B
分別向?qū)Ψ桨l(fā)送了SYN
和ACK
控制消息饶深,等待通信雙方都獲取到了自己期望的初始化序列號(hào)之后就開始通信了餐曹,由于TCP消息頭的設(shè)計(jì),我們可以將中間的兩次通信合成一個(gè)敌厘,TCP B
可以向TCP A
同時(shí)發(fā)送ACK
和SYN
控制消息台猴,這也就幫助我們將四次通信減少至三次。
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 and 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].
除此之外俱两,網(wǎng)絡(luò)作為一個(gè)分布式系統(tǒng)饱狂,其中并不存在一個(gè)用于計(jì)數(shù)的全局時(shí)鐘,而TCP可以通過不同的機(jī)制來初始化序列號(hào)宪彩,作為TCP連接的接收方我們無法判斷對(duì)方傳來的初始化序列號(hào)是否過期休讳,所以我們需要交由對(duì)方來判斷,TCP連接的發(fā)起方可以通過保存發(fā)出的序列號(hào)來判斷連接是否過期尿孔,如果讓接收方來保存并判斷序列號(hào)卻是不現(xiàn)實(shí)的俊柔,這也再一次強(qiáng)化了我們?cè)谏弦还?jié)提出的觀點(diǎn)——避免歷史錯(cuò)連接的初始化筹麸。
通信次數(shù)
當(dāng)我們討論TCP建立連接需要的通信次數(shù)時(shí),我們經(jīng)常執(zhí)著于為什么通信三次才可以建立連接雏婶,而不是兩次或者四次物赶;討論使用更多的通信次數(shù)來建立連接往往是沒有意義的,因?yàn)槲覀兛偸强梢?strong>使用更多的通信次數(shù)交換相同的信息留晚,所以使用四次酵紫、五次或者更多次建立連接在技術(shù)上都是完全可以實(shí)現(xiàn)的。
這種增加TCP連接通信次數(shù)的問題往往討論的必要性错维,我們追求的其實(shí)是用更少的通信次數(shù)(理論上的邊界)完成信息交換憨闰,也就是為什么我們?cè)谏蟽晒?jié)中一再強(qiáng)調(diào)使用「兩次握手」沒有辦法建立TCP連接,使用三次握手是建立連接所需的最小次數(shù)需五。
總結(jié)
我們?cè)谶@篇文章中討論了為什么TCP建立連接需要經(jīng)過三次握手,在具體分析這個(gè)問題之前轧坎,我們首先重新思考了TCP連接究竟是什么宏邮,RFC 793 - Transmission Control Protocol - IETF Tools 對(duì)TCP鏈接有著非常清楚的定義——用于保證可靠性和流控制機(jī)制的數(shù)據(jù),包括Socket缸血、序列號(hào)和窗口大小蜜氨。
TCP建立連接時(shí)通過三次握手可以有效地避免歷史錯(cuò)誤連接信息的建立,減少通信雙方不必要的資源消耗捎泻,三次握手能夠幫助通信雙方獲取初始化序列號(hào)飒炎,它們能夠保證數(shù)據(jù)包傳輸?shù)牟恢夭粊G,還能保證它們的傳輸順序笆豁,不會(huì)因?yàn)榫W(wǎng)絡(luò)傳輸?shù)膯栴}發(fā)生混亂郎汪,到不使用「兩次握手」和「四次握手」的原因已經(jīng)非常清楚了:
- 「兩次握手」:無法避免歷史錯(cuò)誤連接的初始化,浪費(fèi)接收方的資源闯狱;
- 「四次握手」:TCP協(xié)議的設(shè)計(jì)可以讓我們同時(shí)傳遞
ACK
和SYN
兩個(gè)控制信息煞赢,減少了通信次數(shù),所以不需要使用更多的通信次數(shù)傳輸相同的信息哄孤;
我們重新回到在文章開頭提的問題照筑,為什么使用類比解釋TCP使用三次握手是錯(cuò)誤的?這主要還是因?yàn)槭莩拢@個(gè)類比沒有解釋清楚核心問題——避免歷史上的重復(fù)連接凝危。到最后,我們還是來看一些比較開放的相關(guān)問題晨逝,有興趣的讀者可以仔細(xì)想一下下面的問題:
- 除了使用序列號(hào)是否還有其他方式保證消息的不重不丟蛾默?
- UDP協(xié)議有鏈接的概念么,它能保證數(shù)據(jù)傳輸?shù)目煽啃悦矗?/li>