【Unix 网络编程】TCP状态转换图详解
TCP協(xié)議的三路握手和四次揮手。如下圖所示,TCP通信過(guò)程包括三個(gè)步驟:建立TCP連接通道(三次握手)、數(shù)據(jù)傳輸、斷開(kāi)TCP連接通道(四次揮手)。
????????????????????????????????????????????? ?
這里進(jìn)一步探究TCP三路握手和四次揮手過(guò)程中的狀態(tài)變遷以及數(shù)據(jù)傳輸過(guò)程。先看TCP狀態(tài)狀態(tài)轉(zhuǎn)換圖。
??????????????????????????????????????????????????????????????????????????????????? ?
上半部分是TCP三路握手過(guò)程的狀態(tài)變遷,下半部分是TCP四次揮手過(guò)程的狀態(tài)變遷。
??? CLOSED:起始點(diǎn),在超時(shí)或者連接關(guān)閉時(shí)候進(jìn)入此狀態(tài),這并不是一個(gè)真正的狀態(tài),而是這個(gè)狀態(tài)圖的假想起點(diǎn)和終點(diǎn)。
??? LISTEN:服務(wù)器端等待連接的狀態(tài)。服務(wù)器經(jīng)過(guò) socket,bind,listen 函數(shù)之后進(jìn)入此狀態(tài),開(kāi)始監(jiān)聽(tīng)客戶端發(fā)過(guò)來(lái)的連接請(qǐng)求。此稱為應(yīng)用程序被動(dòng)打開(kāi)(等到客戶端連接請(qǐng)求)。
??? SYN_SENT:第一次握手發(fā)生階段,客戶端發(fā)起連接。客戶端調(diào)用 connect,發(fā)送 SYN 給服務(wù)器端,然后進(jìn)入 SYN_SENT 狀態(tài),等待服務(wù)器端確認(rèn)(三次握手中的第二個(gè)報(bào)文)。如果服務(wù)器端不能連接,則直接進(jìn)入CLOSED狀態(tài)。
??? SYN_RCVD:第二次握手發(fā)生階段,跟 3 對(duì)應(yīng),這里是服務(wù)器端接收到了客戶端的 SYN,此時(shí)服務(wù)器由 LISTEN 進(jìn)入 SYN_RCVD狀態(tài),同時(shí)服務(wù)器端回應(yīng)一個(gè) ACK,然后再發(fā)送一個(gè) SYN 即 SYN+ACK 給客戶端。狀態(tài)圖中還描繪了這樣一種情況,當(dāng)客戶端在發(fā)送 SYN 的同時(shí)也收到服務(wù)器端的 SYN請(qǐng)求,即兩個(gè)同時(shí)發(fā)起連接請(qǐng)求,那么客戶端就會(huì)從 SYN_SENT 轉(zhuǎn)換到 SYN_REVD 狀態(tài)。
??? ESTABLISHED:第三次握手發(fā)生階段,客戶端接收到服務(wù)器端的 ACK 包(ACK,SYN)之后,也會(huì)發(fā)送一個(gè) ACK 確認(rèn)包,客戶端進(jìn)入 ESTABLISHED 狀態(tài),表明客戶端這邊已經(jīng)準(zhǔn)備好,但TCP 需要兩端都準(zhǔn)備好才可以進(jìn)行數(shù)據(jù)傳輸。服務(wù)器端收到客戶端的 ACK 之后會(huì)從 SYN_RCVD 狀態(tài)轉(zhuǎn)移到 ESTABLISHED 狀態(tài),表明服務(wù)器端也準(zhǔn)備好進(jìn)行數(shù)據(jù)傳輸了。這樣客戶端和服務(wù)器端都是 ESTABLISHED 狀態(tài),就可以進(jìn)行后面的數(shù)據(jù)傳輸了。所以 ESTABLISHED 也可以說(shuō)是一個(gè)數(shù)據(jù)傳送狀態(tài)。
上面就是 TCP 三次握手過(guò)程的狀態(tài)變遷。結(jié)合第一張三次握手過(guò)程圖,從報(bào)文的角度看狀態(tài)變遷:SYN_SENT 狀態(tài)表示已經(jīng)客戶端已經(jīng)發(fā)送了 SYN 報(bào)文,SYN_RCVD 狀態(tài)表示服務(wù)器端已經(jīng)接收到了 SYN 報(bào)文。
下面看看TCP四次揮手過(guò)程的狀態(tài)變遷。結(jié)合第一張四次揮手過(guò)程圖來(lái)理解。
??? FIN_WAIT_1:第一次揮手。主動(dòng)關(guān)閉的一方(執(zhí)行主動(dòng)關(guān)閉的一方既可以是客戶端,也可以是服務(wù)器端,這里以客戶端執(zhí)行主動(dòng)關(guān)閉為例),終止連接時(shí),發(fā)送 FIN 給對(duì)方,然后等待對(duì)方返回 ACK 。調(diào)用 close() 第一次揮手就進(jìn)入此狀態(tài)。
??? CLOSE_WAIT:接收到FIN 之后,被動(dòng)關(guān)閉的一方進(jìn)入此狀態(tài)。具體動(dòng)作是接收到 FIN,同時(shí)發(fā)送 ACK。之所以叫 CLOSE_WAIT 可以理解為被動(dòng)關(guān)閉的一方此時(shí)正在等待上層應(yīng)用程序發(fā)出關(guān)閉連接指令。前面已經(jīng)說(shuō)過(guò),TCP關(guān)閉是全雙工過(guò)程,這里客戶端執(zhí)行了主動(dòng)關(guān)閉,被動(dòng)方服務(wù)器端接收到FIN 后也需要調(diào)用 close 關(guān)閉,這個(gè) CLOSE_WAIT 就是處于這個(gè)狀態(tài),等待發(fā)送 FIN,發(fā)送了FIN 則進(jìn)入 LAST_ACK 狀態(tài)。
??? FIN_WAIT_2:主動(dòng)端(這里是客戶端)先執(zhí)行主動(dòng)關(guān)閉發(fā)送FIN,然后接收到被動(dòng)方返回的 ACK 后進(jìn)入此狀態(tài)。
??? LAST_ACK:被動(dòng)方(服務(wù)器端)發(fā)起關(guān)閉請(qǐng)求,由狀態(tài)2 進(jìn)入此狀態(tài),具體動(dòng)作是發(fā)送 FIN給對(duì)方,同時(shí)在接收到ACK 時(shí)進(jìn)入CLOSED狀態(tài)。
??? CLOSING:兩邊同時(shí)發(fā)起關(guān)閉請(qǐng)求時(shí)(即主動(dòng)方發(fā)送FIN,等待被動(dòng)方返回ACK,同時(shí)被動(dòng)方也發(fā)送了FIN,主動(dòng)方接收到了FIN之后,發(fā)送ACK給被動(dòng)方),主動(dòng)方會(huì)由FIN_WAIT_1 進(jìn)入此狀態(tài),等待被動(dòng)方返回ACK。
??? TIME_WAIT:從狀態(tài)變遷圖會(huì)看到,四次揮手操作最后都會(huì)經(jīng)過(guò)這樣一個(gè)狀態(tài)然后進(jìn)入CLOSED狀態(tài)。共有三個(gè)狀態(tài)會(huì)進(jìn)入該狀態(tài)
??? 由CLOSING進(jìn)入:同時(shí)發(fā)起關(guān)閉情況下,當(dāng)主動(dòng)端接收到ACK后,進(jìn)入此狀態(tài),實(shí)際上這里的同時(shí)是這樣的情況:客戶端發(fā)起關(guān)閉請(qǐng)求,發(fā)送FIN之后等待服務(wù)器端回應(yīng)ACK,但此時(shí)服務(wù)器端同時(shí)也發(fā)起關(guān)閉請(qǐng)求,也發(fā)送了FIN,并且被客戶端先于ACK接收到。
??? 由FIN_WAIT_1進(jìn)入:發(fā)起關(guān)閉后,發(fā)送了FIN,等待ACK的時(shí)候,正好被動(dòng)方(服務(wù)器端)也發(fā)起關(guān)閉請(qǐng)求,發(fā)送了FIN,這時(shí)客戶端接收到了先前ACK,也收到了對(duì)方的FIN,然后發(fā)送ACK(對(duì)對(duì)方FIN的回應(yīng)),與CLOSING進(jìn)入的狀態(tài)不同的是接收到FIN和ACK的先后順序。
??? 由FIN_WAIT_2進(jìn)入:這是不同時(shí)的情況,主動(dòng)方在完成自身發(fā)起的主動(dòng)關(guān)閉請(qǐng)求后,接收到了對(duì)方發(fā)送過(guò)來(lái)的FIN,然后回應(yīng) ACK。
下面來(lái)看看這個(gè)看似有點(diǎn)多余的TIME_WAIT狀態(tài):從上面進(jìn)入TIME_WAIT狀態(tài)的三個(gè)狀態(tài)動(dòng)作來(lái)看(可以直接看狀態(tài)變遷圖)都是主動(dòng)方最后回應(yīng)一個(gè)ACK(CLOSING實(shí)際上前面的那個(gè)FIN_WAIT_1狀態(tài)就已經(jīng)回應(yīng)了ACK)。
先考慮這樣的一個(gè)情況,假如這個(gè)最后回應(yīng)的ACK丟失了,也就是服務(wù)器端接收不到這個(gè)ACK,那么服務(wù)器將繼續(xù)發(fā)送它最終的那個(gè)FIN,因此客戶端必須維護(hù)狀態(tài)信息(TIME_WAIT)允許它重發(fā)最后的那個(gè)ACK。如果沒(méi)有這個(gè)TIME_WAIT狀態(tài),客戶端處于CLOSED狀態(tài)(開(kāi)頭就說(shuō)了CLOSED狀態(tài)實(shí)際并不存在,是我們?yōu)榱朔奖忝枋黾傧氲?#xff09;,那么客戶端將響應(yīng)RST,服務(wù)器端收到后會(huì)將該RST分節(jié)解釋成一個(gè)錯(cuò)誤,也就不能實(shí)現(xiàn)最后的全雙工關(guān)閉了(可能是主動(dòng)方單方的關(guān)閉)。所以要實(shí)現(xiàn)TCP全雙工連接的正常終止(兩方都關(guān)閉連接),必須處理終止過(guò)程中四個(gè)分節(jié)任何一個(gè)分節(jié)的丟失情況,那么主動(dòng)關(guān)閉連接的主動(dòng)端必須維持TIME_WAIT狀態(tài),最后一個(gè)回應(yīng)ACK的是主動(dòng)執(zhí)行關(guān)閉的那端。從變遷圖可以看出,如果沒(méi)有TIME_WAIT狀態(tài),我們將沒(méi)有任何機(jī)制來(lái)保證最后一個(gè)ACK能夠正常到達(dá)。前面的FIN,ACK正常到達(dá)均有相應(yīng)的狀態(tài)對(duì)應(yīng)。
還有這樣一種情況,如果目前的通信雙方都已經(jīng)調(diào)用了 close(),都到達(dá)了CLOSED狀態(tài),沒(méi)有TIME_WAIT狀態(tài)時(shí),會(huì)出現(xiàn)這樣一種情況,現(xiàn)在有一個(gè)新的連接被建立起來(lái),使用的IP地址和端口和這個(gè)先前到達(dá)了CLOSED狀態(tài)的完全相同,假定原先的連接中還有數(shù)據(jù)報(bào)殘存在網(wǎng)絡(luò)之中,這樣新的連接建立以后傳輸?shù)臄?shù)據(jù)極有可能就是原先的連接的數(shù)據(jù)報(bào),為了防止這一點(diǎn),TCP不允許從處于TIME_WAIT狀態(tài)的socket 建立一個(gè)連接。處于TIME_WAIT狀態(tài)的 socket 在等待了兩倍的MSL時(shí)間之后,將會(huì)轉(zhuǎn)變?yōu)镃LOSED狀態(tài)。這里TIME_WAIT狀態(tài)持續(xù)的時(shí)間是2MSL(MSL是任何IP數(shù)據(jù)報(bào)能夠在因特網(wǎng)中存活的最長(zhǎng)時(shí)間),足以讓這兩個(gè)方向上的數(shù)據(jù)包被丟棄(最長(zhǎng)是2MSL)。通過(guò)實(shí)施這個(gè)規(guī)則,我們就能保證每成功建立一個(gè)TCP連接時(shí),來(lái)自該連接先前化身的老的重復(fù)分組都已經(jīng)在網(wǎng)絡(luò)中消逝了。
? 綜上來(lái)看:TIME_WAIT存在的兩個(gè)理由就是
??? 可靠地實(shí)現(xiàn)TCP全雙工連接的終止;
??? 允許老的重復(fù)分節(jié)(數(shù)據(jù)報(bào))在網(wǎng)絡(luò)中消逝。
參考資料《UNP》《TCP/IP Vol.1》
————————————————
原文鏈接:https://blog.csdn.net/wenqian1991/article/details/40110703
總結(jié)
以上是生活随笔為你收集整理的【Unix 网络编程】TCP状态转换图详解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 常用对照表之TCP及UDP常见端口参照
- 下一篇: 结构体struct timeval 和