前言
- 眾所周知tcp傳輸層協(xié)議在建立連接的時(shí)候需要三次才能建立起一個(gè)真正的可靠連接齐遵,可是為什么是三次呢氮采,不可以是兩次谋逻,四次等等呢呆馁,可以自己思考一番,帶著疑問可以看下文毁兆。
三次握手
在《計(jì)算機(jī)網(wǎng)絡(luò)》一書中其中有提到浙滤,三次握手的目的是“為了防止已經(jīng)失效的連接請(qǐng)求報(bào)文段突然又傳到服務(wù)端,因而產(chǎn)生錯(cuò)誤”气堕,這種情況是:一端(client)A發(fā)出去的第一個(gè)連接請(qǐng)求報(bào)文并沒有丟失纺腊,而是因?yàn)槟承┪粗脑蛟谀硞€(gè)網(wǎng)絡(luò)節(jié)點(diǎn)上發(fā)生滯留畔咧,導(dǎo)致延遲到連接釋放以后的某個(gè)時(shí)間才到達(dá)另一端(server)B。本來這是一個(gè)早已失效的報(bào)文段揖膜,但是B收到此失效的報(bào)文之后誓沸,會(huì)誤認(rèn)為是A再次發(fā)出的一個(gè)新的連接請(qǐng)求,于是B端就向A又發(fā)出確認(rèn)報(bào)文壹粟,表示同意建立連接拜隧。如果不采用“三次握手”,那么只要B端發(fā)出確認(rèn)報(bào)文就會(huì)認(rèn)為新的連接已經(jīng)建立了趁仙,但是A端并沒有發(fā)出建立連接的請(qǐng)求洪添,因此不會(huì)去向B端發(fā)送數(shù)據(jù),B端沒有收到數(shù)據(jù)就會(huì)一直等待雀费,這樣B端就會(huì)白白浪費(fèi)掉很多資源干奢。如果采用“三次握手”的話就不會(huì)出現(xiàn)這種情況,B端收到一個(gè)過時(shí)失效的報(bào)文段之后盏袄,向A端發(fā)出確認(rèn)忿峻,此時(shí)A并沒有要求建立連接,所以就不會(huì)向B端發(fā)送確認(rèn)貌矿,這個(gè)時(shí)候B端也能夠知道連接沒有建立炭菌。
問題的本質(zhì)是,信道是不可靠的逛漫,但是我們要建立可靠的連接發(fā)送可靠的數(shù)據(jù)黑低,也就是數(shù)據(jù)傳輸是需要可靠的。在這個(gè)時(shí)候三次握手是一個(gè)理論上的最小值酌毡,并不是說是tcp協(xié)議要求的克握,而是為了滿足在不可靠的信道上傳輸可靠的數(shù)據(jù)所要求的。
我們?cè)賮砜紤]枷踏,如果不是三次握手會(huì)出現(xiàn)什么情況呢:
假設(shè)有A和B兩端要進(jìn)行通信菩暗,
1, 第一次:首先A發(fā)送一個(gè)(SYN)到B,意思是A要和B建立連接進(jìn)行通信旭蠕;如果是只有一次握手的話停团,這樣肯定是不行的,A壓根都不知道B是不是收到了這個(gè)請(qǐng)求掏熬。
2, 第二次:B收到A要建立連接的請(qǐng)求之后佑稠,發(fā)送一個(gè)確認(rèn)(SYN+ACK)給A,意思是收到A的消息了旗芬,B這里也是通的舌胶,表示可以建立連接;
如果只有兩次通信的話疮丛,這時(shí)候B不確定A是否收到了確認(rèn)消息幔嫂,有可能這個(gè)確認(rèn)消息由于某些原因丟了辆它。
3, 第三次:A如果收到了B的確認(rèn)消息之后,再發(fā)出一個(gè)確認(rèn)(ACK)消息履恩,意思是告訴B锰茉,這邊是通的,然后A和B就可以建立連接相互通信了似袁;
這個(gè)時(shí)候經(jīng)過了三次握手洞辣,A和B雙方確認(rèn)了兩邊都是通的,可以相互通信了昙衅,已經(jīng)可以建立一個(gè)可靠的連接,并且可以相互發(fā)送數(shù)據(jù)定鸟。
4, 第四次:這個(gè)時(shí)候已經(jīng)不需要B再發(fā)送一個(gè)確認(rèn)消息了而涉,兩邊已經(jīng)通過前三次建立了一個(gè)可靠的連接,如果再發(fā)送第四次確認(rèn)消息的話联予,就浪費(fèi)資源了啼县。
如果第二個(gè)報(bào)文段B發(fā)出的(SYN+ACK)分別發(fā)送的話,也是可以理解為四次沸久,但是被優(yōu)化了季眷,一起發(fā)送了。
- 超時(shí)重傳機(jī)制卷胯,
(1) 如果第一個(gè)包子刮,A發(fā)送給B請(qǐng)求建立連接的報(bào)文(SYN)如果丟掉了,A會(huì)周期性的超時(shí)重傳窑睁,直到B發(fā)出確認(rèn)(SYN+ACK)挺峡;
(2) 如果第二個(gè)包,B發(fā)送給A的確認(rèn)報(bào)文(SYN+ACK)如果丟掉了担钮,B會(huì)周期性的超時(shí)重傳橱赠,直到A發(fā)出確認(rèn)(ACK);
(3) 如果第三個(gè)包箫津,A發(fā)送給B的確認(rèn)報(bào)文(ACK)如果丟掉了狭姨,
- A在發(fā)送完確認(rèn)報(bào)文之后,單方面會(huì)進(jìn)入ESTABLISHED的狀態(tài)苏遥,B還是SYN_RCVD狀態(tài)
- 如果此時(shí)雙方都沒有數(shù)據(jù)需要發(fā)送饼拍,B會(huì)周期性的超時(shí)發(fā)送(SYN+ACK),直到收到A的確認(rèn)報(bào)文(ACK)暖眼,此時(shí)B也進(jìn)入ESTABLISHED狀態(tài)惕耕,雙方可以發(fā)送數(shù)據(jù);
- 如果A有數(shù)據(jù)發(fā)送诫肠,A發(fā)送的是(ACK+DATA)司澎,B會(huì)在收到這個(gè)數(shù)據(jù)包的時(shí)候自動(dòng)切換到ESTABLISHED狀態(tài)欺缘,并接受數(shù)據(jù)(DATA);
- 如果這個(gè)時(shí)候B要發(fā)送數(shù)據(jù)挤安,B是發(fā)送不了數(shù)據(jù)的谚殊,會(huì)周期性的超時(shí)重傳(SYN+ACK)直到收到A的確認(rèn)(ACK)B才能發(fā)送數(shù)據(jù)。
- 三次握手牽扯到的狀態(tài)轉(zhuǎn)換
- ** LISTEN ** 表示socket已經(jīng)處于listen狀態(tài)了蛤铜,可以建立連接嫩絮;
- ** SYN_SENT ** 表示socket在發(fā)出connect連接的時(shí)候,會(huì)首先發(fā)送SYN報(bào)文围肥,然后等待另一端發(fā)送的確認(rèn)報(bào)文(ACK)剿干,表示這端已經(jīng)發(fā)送完SYN報(bào)文了;
- ** SYN_RCVD ** 表示一端已經(jīng)接收到SYN報(bào)文了穆刻;
- ** ESTABLISHED ** 表示已經(jīng)建立連接了置尔,可以發(fā)送數(shù)據(jù)了。
四次揮手
- 說完TCP建立連接的時(shí)候?yàn)槭裁词侨吻馕埃鄬?duì)的就會(huì)想到為什么斷開連接的時(shí)候是需要四次呢榜轿,而不是三次,五次等等呢朵锣;
- 本質(zhì)的原因是tcp是全雙公的谬盐,要實(shí)現(xiàn)可靠的連接關(guān)閉,A發(fā)出結(jié)束報(bào)文FIN诚些,收到B確認(rèn)后A知道自己沒有數(shù)據(jù)需要發(fā)送了飞傀,B知道A不再發(fā)送數(shù)據(jù)了,自己也不會(huì)接收數(shù)據(jù)了泣刹,但是此時(shí)A還是可以接收數(shù)據(jù)助析,B也可以發(fā)送數(shù)據(jù);當(dāng)B發(fā)出FIN報(bào)文的時(shí)候此時(shí)兩邊才會(huì)真正的斷開連接椅您,讀寫分開外冀。
- 四次揮手牽扯到的狀態(tài)裝換
- ** FIN_WAIT_1 ** 表示在等待另一方的FIN報(bào)文,和FIN_WAIT_2的區(qū)別是掀泳,F(xiàn)IN_WAIT_1表示socket現(xiàn)在要主動(dòng)關(guān)閉連接雪隧,在發(fā)送完FIN報(bào)文后socket進(jìn)入FIN_WAIT_1狀態(tài),當(dāng)收到另一方發(fā)送FIN的ACK之后立即進(jìn)入FIN_WAIT_2狀態(tài)员舵;
- ** FIN_WAIT_2 ** 同上脑沿,此時(shí)需要做的事情是可能還會(huì)接收數(shù)據(jù),然后等待另一方的FIN马僻;
- ** TIME_WAIT ** 存在主動(dòng)關(guān)閉的一方庄拇,表示收到了對(duì)方的FIN報(bào)文,并發(fā)送出了ACK報(bào)文,就等2MSL(Max Segment Lifetime))后即可回到CLOSED可用狀態(tài)了措近,需要等一段時(shí)間時(shí)原因是網(wǎng)絡(luò)是不可靠的溶弟,不能保證這個(gè)ACK發(fā)送成功了,如果失敗了瞭郑,對(duì)端會(huì)超時(shí)重傳FIN辜御;
- ** CLOSING ** 表示在發(fā)送FIN之后,沒有收到對(duì)方的ACK屈张,而是收到了對(duì)方的FIN擒权,這中情況很少見,只有在兩端幾乎同時(shí)關(guān)閉同一個(gè)socket的時(shí)候才會(huì)出現(xiàn)CLOSING狀態(tài)阁谆;
- ** CLOSE_WAIT ** 表示收到對(duì)方的FIN之后碳抄,回給對(duì)方ACK,此時(shí)處于CLOSE_WAIT狀態(tài)笛厦,等待關(guān)閉纳鼎,要看自己是否還有數(shù)據(jù)要發(fā)送;
- ** LAST_ACK ** 表示收到對(duì)方的FIN之后裳凸,回給對(duì)方ACK,然后自己也要關(guān)閉發(fā)送FIN劝贸,等待另一方的ACK時(shí)候的狀態(tài)姨谷;
- ** CLOSED ** 這個(gè)狀態(tài)表示連接已經(jīng)斷開。
-
最后放一張狀態(tài)轉(zhuǎn)換圖
三次握手和四次揮手狀態(tài)轉(zhuǎn)換圖
后記
- 在狀態(tài)轉(zhuǎn)換圖中省略了數(shù)據(jù)的發(fā)送映九;
- 對(duì)于tcp/ip的學(xué)習(xí)還需要努力梦湘,可能文中有些表達(dá)不夠嚴(yán)謹(jǐn),還望海涵件甥。
*** 如有疑問歡迎批評(píng)指正捌议,謝謝! ***