看到了一道面試題:“為什么TCP建立連接協(xié)議是三次握手低散,而關(guān)閉連接卻是四次握手呢俯邓?為什么不能用兩次握手進(jìn)行連接?”熔号,想想最近也到金三銀四了稽鞭,所以就查閱了相關(guān)資料,整理出來了這篇文章引镊,希望對(duì)你們有所幫助朦蕴。
TCP 連接
我們先來補(bǔ)一下基礎(chǔ)什么是 TCP 協(xié)議?傳輸控制協(xié)議( Transmission Control Protocol, TCP )是種面向連接弟头、確保數(shù)據(jù)在端到端間可靠傳輸?shù)膮f(xié)議吩抓。面向連接是插在發(fā)送數(shù)據(jù)前,需要先建立一條虛擬的鏈路赴恨,然后讓數(shù)據(jù)在這條鏈路上“流動(dòng)”完成傳輸疹娶。
TCP 是可靠的,會(huì)盡自己最大的努力去完成數(shù)據(jù)傳輸伦连,TCP 協(xié)議比較復(fù)雜雨饺,內(nèi)容非常的豐富,跟我們今天要討論的連接協(xié)議相關(guān)的就是中間那六個(gè)狀態(tài)位: URG惑淳、ACK额港、PSH、RST歧焦、SYN移斩、FIN ,都置為 1 表示有效,在這六個(gè)當(dāng)中叹哭,我們主要關(guān)注重點(diǎn)關(guān)注 ACK忍宋、SYN、FIN 這三個(gè)风罩。下面解釋一下這三個(gè)狀態(tài)位:
ACK:用于對(duì)收到的數(shù)據(jù)進(jìn)行確認(rèn),所確認(rèn)的數(shù)據(jù)由確認(rèn)序列號(hào)表示舵稠。
SYN:用作建立連接時(shí)的同步信號(hào)
FIN:表示后面沒有數(shù)據(jù)需要發(fā)送超升,通常意昧著所建立的連接需要關(guān)閉了。
好了哺徊,到這里室琢,TCP 的基礎(chǔ)知識(shí)我們就知道了,下面我們就來看看為什么
是三次握手落追,而不是四次或者兩次盈滴,為了讓你更好的理解,我把知乎上一個(gè)高贊特別形象的比喻放在這里轿钠,希望對(duì)你有所幫助巢钓。
兩次和四次都會(huì)出現(xiàn)問題,三次就剛剛好疗垛,希望這張圖能夠讓你更好的理解為什么是三次握手症汹。
我們已經(jīng)知道了 TCP 協(xié)議是三次握手,為什么是三次握手呢贷腕?
總體來說就是呼叫背镇、應(yīng)答、回應(yīng)泽裳,我們來詳細(xì)的介紹每一步:
第一步: A 機(jī)器向 B機(jī)器發(fā)出一個(gè)數(shù)據(jù)包并將 SYN 設(shè)置為 1 瞒斩,表示希望建立連接。這個(gè)包中的序列號(hào)假設(shè)是 X涮总。
第二步: B 機(jī)器收到 A機(jī)器發(fā)過來的數(shù)據(jù)包后胸囱,通過 SYN 得知這是一個(gè)建立連接的請(qǐng)求,于是發(fā)送一個(gè)響應(yīng)包并將 SYN 妹卿、ACK 標(biāo)記都置為 1旺矾。假設(shè)這個(gè)包中的序列號(hào)是 y ,而確認(rèn)序列號(hào)必須是 x+l 夺克,表示收到了 發(fā)過來的 SYN箕宙,TCP 中, SYN 被當(dāng)作數(shù)據(jù)部分的一個(gè)字節(jié)铺纽。
第三步: A 收到 的響應(yīng)包后需進(jìn)行確認(rèn)柬帕,確認(rèn)包中將 ACK ,并將確認(rèn)序列號(hào)設(shè)置為 y+ ,表示收到了來自B 的 SYN
經(jīng)過這三步之后陷寝,兩臺(tái)服務(wù)器就建立連接了锅很,可以進(jìn)行通信數(shù)據(jù)傳輸了。為什么要三次握手呢凤跑?主要是為了信息對(duì)等和防止出現(xiàn)請(qǐng)求超時(shí)導(dǎo)致臟連接爆安。
第一是為了保證兩臺(tái)機(jī)器信息對(duì)等,確保兩臺(tái)機(jī)器都沒有什么問題:
只有三次握手之后才能夠保證兩臺(tái)服務(wù)器都完全沒有問題仔引,各自具備發(fā)報(bào)和收?qǐng)?bào)能力扔仓。
第二是防止出現(xiàn)請(qǐng)求超時(shí)導(dǎo)致臟連接。
為什么會(huì)出現(xiàn)臟連接咖耘?因?yàn)門TL 網(wǎng)絡(luò)報(bào)文的生存時(shí)間往往都會(huì)超 TCP 請(qǐng)求超時(shí)時(shí)間翘簇,如果兩次握手就可以創(chuàng)建連接 ,傳輸數(shù)據(jù)并釋放連接后儿倒,第一個(gè)超時(shí)的連接請(qǐng)求才到達(dá) B 機(jī)器的話版保,B 機(jī)器會(huì)以為是 A 創(chuàng)建新連接的請(qǐng)求,然后確認(rèn)同意創(chuàng)建連接夫否。因?yàn)?A 機(jī)器的狀態(tài)不是 SYl_SENT 彻犁,所以直接丟棄了 B 的確認(rèn)數(shù)據(jù) ,以致最后只是 B 機(jī)器單方面創(chuàng)建連接完畢慷吊。
三次握手就可以解決這個(gè)問題袖裕,因?yàn)樾枰?A 服務(wù)器確認(rèn)了才真正的建立了連接。
TCP 四次揮手
上面介紹了 TCP 協(xié)議連接溉瓶,有連接就有斷開急鳄,相對(duì)于三次連接,斷開卻需要四次揮手堰酿,怎么理解呢疾宏?先看下面這個(gè)場(chǎng)景:
A:B 啊,我不想玩了触创。
B:哦坎藐,你不想玩了啊,我知道了哼绑。
這個(gè)時(shí)候岩馍,還只是 A 不想玩了,也即 A 不會(huì)再發(fā)送數(shù)據(jù)抖韩,但是 B 能不能在 ACK 的時(shí)候蛀恩,直接關(guān)閉呢?當(dāng)然不可以了茂浮,很有可能 A 是發(fā)完了最后的數(shù)據(jù)就準(zhǔn)備不玩了双谆,但是 B 還沒做完自己的事情壳咕,還是可以發(fā)送數(shù)據(jù)的,所以稱為半關(guān)閉的狀態(tài)顽馋。
這個(gè)時(shí)候 A 可以選擇不再接收數(shù)據(jù)了谓厘,也可以選擇最后再接收一段數(shù)據(jù),等待 B 也主動(dòng)關(guān)閉寸谜。
B:A 啊竟稳,好吧,我也不玩了程帕,拜拜住练。
A:好的,拜拜愁拭。
這就是一個(gè)完整的關(guān)閉連接,在這個(gè)關(guān)閉的過程中亏吝,一共說了四句話岭埠,我們也稱之為四次揮手。跟建立連接一樣蔚鸥,斷開時(shí)也是用狀態(tài)來表示惜论。
我們結(jié)合上面的時(shí)序圖和場(chǎng)景再來分析一下 TCP 斷開過程。
當(dāng) A 說“不玩了”止喷,A 就進(jìn)入 FIN_WAIT_1 的狀態(tài)馆类,B 收到“A 不玩”的消息后,發(fā)送知道了弹谁,B 就進(jìn)入 CLOSE_WAIT 的狀態(tài)乾巧。
A 收到“B 說知道了”,就進(jìn)入 FIN_WAIT_2 的狀態(tài)预愤,如果這個(gè)時(shí)候 B 直接跑路沟于,則 A 將永遠(yuǎn)在這個(gè)狀態(tài)。雖然 TCP 協(xié)議里面并沒有對(duì)這個(gè)狀態(tài)的處理植康,但是 Linux 有旷太,可以調(diào)整 tcp_fin_timeout 這個(gè)參數(shù),設(shè)置一個(gè)超時(shí)時(shí)間销睁,最后 A 也會(huì)關(guān)閉的供璧。
如果 B 沒有跑路,發(fā)送了“B 也不玩了”的請(qǐng)求到達(dá) A 時(shí)冻记,A 發(fā)送“知道 B 也不玩了”的 ACK 后睡毒,從 FIN_WAIT_2 狀態(tài)結(jié)束,按說 A 可以跑路了檩赢,但是最后的這個(gè) ACK 萬一 B 收不到呢吕嘀?則 B 會(huì)重新發(fā)一個(gè)“B 不玩了”违寞,這個(gè)時(shí)候 A 已經(jīng)跑路了的話,B 就再也收不到 ACK 了偶房,因而 TCP 協(xié)議要求 A 最后等待一段時(shí)間 TIME_WAIT趁曼,這個(gè)時(shí)間要足夠長,長到如果 B 沒收到 ACK 的話棕洋,“B 說不玩了”會(huì)重發(fā)的挡闰,A 會(huì)重新發(fā)一個(gè) ACK 并且足夠時(shí)間到達(dá) B。
要求 A 等待 TIME_WAIT還有一個(gè)原因就是防止產(chǎn)生混亂掰盘,A 直接關(guān)閉了摄悯,但是這個(gè)時(shí)候 B是不知道的,可能在 A 關(guān)閉之前 B還發(fā)送了很多數(shù)據(jù)包愧捕,如果這時(shí)候 A 的端口被一個(gè)新的應(yīng)用占用了的話奢驯,那么新的應(yīng)用就會(huì)接收到上個(gè)連接中 B發(fā)送過來的數(shù)據(jù)包,這樣就混亂了次绘,雖然這個(gè)數(shù)據(jù)包是無效的瘪阁,但是等待 TIME_WAIT 可以是一個(gè)雙保險(xiǎn),因而也需要等足夠長的時(shí)間邮偎,等到原來 B 發(fā)送的所有的包都死翹翹管跺,再空出端口來。
以上就是 TCP 協(xié)議三次握手禾进,四次揮手的原因豁跑,希望這篇文章對(duì)您的學(xué)習(xí)或者工作有所幫助,如果您覺得文章不錯(cuò)泻云,還請(qǐng)您幫忙點(diǎn)個(gè)贊和轉(zhuǎn)發(fā)艇拍,謝謝。
最后
目前互聯(lián)網(wǎng)上很多大佬都有 TCP 協(xié)議相關(guān)文章壶愤,如有雷同淑倾,請(qǐng)多多包涵了。原創(chuàng)不易征椒,碼字不易娇哆,還希望大家多多支持。若文中有所錯(cuò)誤之處勃救,還望提出碍讨,謝謝。