前言
本文將會首先介紹TCP的各個狀態(tài)预厌,然后描述TCP三次握手和四次揮手時的狀態(tài)變化畴蹭,最后重點介紹TIME_WAIT狀態(tài)鼎天。
TCP連接狀態(tài)
一個TCP連接在它的生命周期內(nèi)會有不同的狀態(tài)晦鞋。
下圖說明了TCP連接可能會有的狀態(tài),以及基于事件的狀態(tài)轉(zhuǎn)換艘虎。事件中有的是應(yīng)用程序的操作豫尽,有的是接收到了網(wǎng)絡(luò)發(fā)過來的請求。
TCP狀態(tài)及其描述如下表顷帖。
狀態(tài) | 描述 |
---|---|
LISTEN | 等待來自遠(yuǎn)程TCP應(yīng)用程序的請求 |
SYN_SENT | 發(fā)送連接請求后等待來自遠(yuǎn)程端點的確認(rèn)美旧。TCP第一次握手后客戶端所處的狀態(tài) |
SYN-RECEIVED | 該端點已經(jīng)接收到連接請求并發(fā)送確認(rèn)。 該端點正在等待最終確認(rèn)贬墩。TCP第二次握手后服務(wù)端所處的狀態(tài) |
ESTABLISHED | 代表連接已經(jīng)建立起來了榴嗅。這是連接數(shù)據(jù)傳輸階段的正常狀態(tài) |
FIN_WAIT_1 | 等待來自遠(yuǎn)程TCP的終止連接請求或終止請求的確認(rèn) |
FIN_WAIT_2 | 在此端點發(fā)送終止連接請求后,等待來自遠(yuǎn)程TCP的連接終止請求 |
CLOSE_WAIT | 該端點已經(jīng)收到來自遠(yuǎn)程端點的關(guān)閉請求陶舞,此TCP正在等待本地應(yīng)用程序的連接終止請求 |
CLOSING | 等待來自遠(yuǎn)程TCP的連接終止請求確認(rèn) |
LAST_ACK | 等待先前發(fā)送到遠(yuǎn)程TCP的連接終止請求的確認(rèn) |
TIME_WAIT | 等待足夠的時間來確保遠(yuǎn)程TCP接收到其連接終止請求的確認(rèn) |
TCP三次握手
當(dāng)一個TCP連接建立時嗽测,發(fā)生了以下事情:
- 服務(wù)端必須準(zhǔn)備接收傳入的連接。這通常通過調(diào)用
socket
肿孵,bind
和listen
來完成唠粥,稱為被動打開。 - 客戶端通過調(diào)用
connect
方法來發(fā)起一個主動的打開停做∥罾ⅲ客戶端TCP會發(fā)送一個“同步”(SYN)段,它告訴服務(wù)器客戶端在連接上發(fā)送的數(shù)據(jù)的初始序列號蛉腌。通常情況下官份,SYN沒有發(fā)送數(shù)據(jù),它只包含一個IP頭烙丛,TCP頭和可能的TCP選項舅巷。 - 服務(wù)器必須確認(rèn)(ACK)客戶端的SYN,并且服務(wù)器還必須發(fā)送自己的SYN河咽,其中包含服務(wù)器將在連接上發(fā)送的數(shù)據(jù)的初始序列號钠右。
- 客戶端必須確認(rèn)服務(wù)器的SYN。
下圖顯示了TCP三次握手的過程忘蟹,以及客戶端和服務(wù)端狀態(tài)的變化飒房。
TCP四次揮手
一個TCP連接需要四步斷開:
- 一個應(yīng)用程序首先執(zhí)行
close
,發(fā)送FIN段寒瓦,這個操作被稱為主動關(guān)閉情屹,這意味著這一端完成數(shù)據(jù)的發(fā)送。 - 執(zhí)行FIN的另一端執(zhí)行被動關(guān)閉杂腰,該端發(fā)送ACK,確認(rèn)該FIN椅文。
- 被動關(guān)閉的一端執(zhí)行
close
喂很,向主動關(guān)閉的一方發(fā)送FIN惜颇。 - 主動關(guān)閉的一方確認(rèn)收到的FIN。
下圖顯示了一次典型的TCP四次揮手的過程少辣,以及主動關(guān)閉方和被動關(guān)閉方的狀態(tài)變化凌摄。在圖中是客戶端主動斷開了連接,這里只是舉個例子漓帅,服務(wù)端一樣可以主動斷開連接锨亏。
TIME_WAIT狀態(tài)
TIME_WAIT狀態(tài)應(yīng)該是最讓人疑惑的一個狀態(tài)了。在上圖中可以看到忙干,執(zhí)行主動斷開的節(jié)點最后會進(jìn)入這個狀態(tài)器予,該節(jié)點會在此狀態(tài)保存2倍的MSL(最大段生存期)。
TCP的每個實現(xiàn)都必須為MSL選擇一個值捐迫。RFC 1122推薦的值為兩分鐘乾翔,伯克利派的實現(xiàn)使用30秒。這也就是說TIME_WAIT狀態(tài)會維持1到4分鐘施戴。MSL是任何IP數(shù)據(jù)報可以在網(wǎng)絡(luò)中生存的最長時間反浓。這個時間是有限制的,因為每個數(shù)據(jù)報都包含一個8位的跳數(shù)限制赞哗,最大值是255.雖然這是一個跳數(shù)限制而不是一個真正的時間限制雷则,但是根據(jù)這個限制來假設(shè)數(shù)據(jù)報的最長生命周期依然是有意義的。
網(wǎng)絡(luò)中數(shù)據(jù)報丟失的原因通常是路由異常肪笋。一旦路由崩潰或者兩個路由之間的鏈路斷開巧婶,路由協(xié)議需要幾秒或幾分鐘才能穩(wěn)定,并找到一條備用路徑涂乌。在這段時間內(nèi)艺栈,可能發(fā)生路由回路。同時假設(shè)丟失是一個TCP數(shù)據(jù)報湾盒,則發(fā)生TCP超時湿右,并且重新發(fā)送分組,重傳的分組通過一些備用路徑達(dá)到最終目的地罚勾。但是一段時間后(該時間小于MSL)毅人,路由循環(huán)被更正,在循環(huán)中丟失的數(shù)據(jù)報被發(fā)送到最終目的地尖殃。這個原始的數(shù)據(jù)報被稱為丟失的副本或漫游副本丈莺。TCP協(xié)議必須處理這些數(shù)據(jù)報。
維持TIME_WAIT有兩個原因:
- 可靠地實現(xiàn)TCP的全雙工連接終止送丰。
- 允許舊的重復(fù)數(shù)據(jù)段在網(wǎng)絡(luò)中過期
在四次揮手中缔俄,假設(shè)最后的ACK丟失了,被動關(guān)閉方會重發(fā)FIN。主動關(guān)閉端必須維護(hù)狀態(tài)俐载,來允許被動關(guān)閉方重發(fā)最后的ACK蟹略;如果它沒有維護(hù)這個狀態(tài),將會對重發(fā)FIN返回RST遏佣,被動關(guān)閉方會認(rèn)為這是個錯誤挖炬。如果TCP正在執(zhí)行徹底終止數(shù)據(jù)流的兩個方向所需的所有工作(即全雙工關(guān)閉),則必須正確處理這四個段中任何一個的丟失状婶。所以執(zhí)行主動關(guān)閉的一方必須在結(jié)束時保持TIME_WAIT狀態(tài):因為它可能必須重傳最后的ACK意敛。
現(xiàn)在來聊維持TIME_WAIT狀態(tài)的第二個原因。假設(shè)在主機12.106.32.254的1500端口和206.168.112.219的21端口之間有一個TCP連接膛虫。此連接關(guān)閉后草姻,在相通的地址和端口建立了另外一個連接。由于IP地址和端口相同走敌,所以后一種連接被稱為先前連接的“化身”碴倾。TCP必須防止連接中的舊副本在稍后再次出現(xiàn),并被誤解為屬于同一連接的新“化身”掉丽。為此跌榔,TCP將不會啟動當(dāng)前處于TIME_WAIT狀態(tài)的連接的新“化身”。由于TIME_WAIT狀態(tài)的持續(xù)時間時兩倍的MSL捶障,因此TCP允許一個方向的數(shù)據(jù)在MSL秒內(nèi)丟失僧须,也允許回復(fù)在一個MSL秒內(nèi)丟失。通過強制執(zhí)行此規(guī)則项炼,可以保證當(dāng)一個TCP連接成功建立時担平,來自先前連接的所有舊的副本在網(wǎng)絡(luò)中已過期。