TCP/IP狀態圖 && TIME_WAIT做用html
在TCP/IP狀態圖中,有不少種的狀態,它們之間有的是能夠互相轉換的,也就是說,從一種狀態轉到另外一種狀態,可是這種轉換不是隨便發送的,是要知足必定的條件。TCP/IP狀態圖看起來更像是自動機。下圖即爲TCP/IP狀態。java
由上圖能夠看出,一共有11種不一樣的狀態。這11種狀態描述以下:服務器
CLOSED:關閉狀態,沒有鏈接活動或正在進行;網絡
LISTEN:監聽狀態,服務器正在等待鏈接進入;併發
SYN_RCVD:收到一個鏈接請求,還沒有確認;socket
SYN_SENT:已經發出鏈接請求,等待確認;函數
ESTABLISHED:鏈接創建,正常數據傳輸狀態;spa
FIN_WAIT 1:(主動關閉)已經發送關閉請求,等待確認;code
FIN_WAIT 2:(主動關閉)收到對方關閉確認,等待對方關閉請求;server
TIME_WAIT:完成雙向關閉,等待全部分組死掉;
CLOSING:雙方同時嘗試關閉,等待對方確認;
CLOSE_WAIT:(被動關閉)收到對方關閉請求,已經確認;
LAST_ACK:(被動關閉)等待最後一個關閉確認,並等待全部分組死掉。
在這11中狀態當中,TIME_WAIT這種狀態是最重要的,也是最難理解的。
1.CLOSED:起始點,在超時或者鏈接關閉時候進入此狀態。
2.LISTEN:服務端在等待鏈接過來時候的狀態,服務端爲此要調用socket,bind,listen函數,就能進入此狀態。此稱爲應用程序被動打開(等待客戶端來鏈接)。
3.SYN_SENT:客戶端發起鏈接,發送SYN給服務器端。若是服務器端不能鏈接,則直接進入CLOSED狀態。
4.SYN_RCVD:跟3對應,服務器端接受客戶端的SYN請求,服務器端由LISTEN狀態進入SYN_RCVD狀態。同時服務器端要回應一個ACK,同時發送一個SYN給客戶端;另一種狀況,客戶端在發起SYN的同時接收到服務器端得SYN請求,客戶端就會由SYN_SENT到SYN_RCVD狀態。
5.ESTABLISHED:服務器端和客戶端在完成3次握手進入狀態,說明已經能夠開始傳輸數據了。
以上是創建鏈接時服務器端和客戶端產生的狀態轉移說明。相對來講比較簡單明瞭,若是你對三次握手比較熟悉,創建鏈接時的狀態轉移仍是很容易理解。
下面,咱們來看看鏈接關閉時候的狀態轉移說明,關閉須要進行4次雙方的交互,還包括要處理一些善後工做(TIME_WAIT狀態),注意,這裏主動關閉的一方或被動關閉的一方不是指特指服務器端或者客戶端,是相對於誰先發起關閉請求來講的:
6.FIN_WAIT_1:主動關閉的一方,由狀態5進入此狀態。具體的動做是發送FIN給對方。
7.FIN_WAIT_2:主動關閉的一方,接收到對方的FIN-ACK(即fin包的迴應包),進入此狀態。
8.CLOSE_WAIT:接收到FIN之後,被動關閉的一方進入此狀態。具體動做是接收到FIN,同時發送ACK。(之因此叫close_wait能夠理解爲被動關閉方此時正在等待上層應用發出關閉鏈接指令)
9.LAST_ACK:被動關閉的一方,發起關閉請求,由狀態8進入此狀態。具體動做是發送FIN給對方,同時在接收到ACK時進入CLOSED狀態。
10.CLOSING:兩邊同時發起關閉請求時,會由FIN_WAIT_1進入此狀態。具體動做是接收到FIN請求,同時響應一個ACK。
11.TIME_WAIT:最糾結的狀態來了。從狀態圖上能夠看出,有3個狀態能夠轉化成它,咱們一一來分析:
a.由FIN_WAIT_2進入此狀態:在雙方不一樣時發起FIN的狀況下,主動關閉的一方在完成自身發起的關閉請求後,接收到被動關閉一方的FIN後進入的狀態。
b.由CLOSING狀態進入:雙方同時發起關閉,都作了發起FIN的請求,同時接收到了FIN並作了ACK的狀況下,由CLOSING狀態進入。
c.由FIN_WAIT_1狀態進入:同時接受到FIN(對方發起),ACK(自己發起的FIN迴應),與b的區別在於自己發起的FIN迴應的ACK先於對方的FIN請求到達,而b是FIN先到達。這種狀況機率最小。
假設最終的 ACK 丟失 , server 將重發 FIN , client 必須維護 TCP 狀態信息以即可以重發最終的 ACK ,不然會發送RST ,結果 server 認爲發生錯誤。 TCP 實現必須可靠地終止鏈接的兩個方向 ( 全雙工關閉 ) , client 必須進 TIME_WAIT狀態,由於 client 可能面臨重發最終 ACK 的情形。先調用 close() 的一方會進入 TIME_WAIT 狀態
若是 TIME_WAIT 狀態保持時間不足夠長 ( 好比小於 2MSL) ,第一個鏈接就正常終止了。 第二個擁有相同相關五元組的鏈接出現,而第一個鏈接的重複報文到達,干擾了第二個鏈接。 TCP 實現必須防止某個鏈接的重複報文在鏈接終止後出現,因此讓 TIME_WAIT 狀態保持時間足夠長 (2MSL) ,鏈接相應方向上的 TCP 報文要麼徹底響應完畢,要麼被丟棄。創建第二個鏈接的時候,不會混淆。
根據《TCP/IP詳解》中的TCP的創建和終止中有關"TCP的終止"的講解
TCP的終止經過雙方的四次握手實現。發起終止的一方執行主動關閉,響應的另外一方執行被動關閉。
發起方更改狀態爲FIN_WAIT_1,關閉應用程序進程,發出一個TCP的FIN段;
接收方收到FIN段,返回一個帶確認序號的ACK,同時向本身對應的進程發送一個文件結束符EOF,同時更改狀態爲CLOSE_WAIT,發起方接到 ACK後狀態更改成FIN_WAIT_2;
接收方關閉應用程序進程,更改狀態爲LAST_ACK,並向對方發出一個TCP的FIN段;
發起方接到FIN後狀態更改成TIME_WAIT,併發出這個FIN的ACK確認。ACK發送成功後(2MSL內)雙方TCP狀態變爲CLOSED。
咱們不難看出上面的顯示的結果的意思。根據TCP協議,主動發起關閉的一方,會進入TIME_WAIT狀態(TCP實現必須可靠地終止鏈接的兩個方向(全雙工關閉)),持續2*MSL (Max Segment Lifetime),缺省爲240秒。
主動關閉的Socket端會進入TIME_WAIT狀態,而且持續2MSL時間長度,MSL就是maximum segment lifetime(最大分節生命期),這是一個IP數據包能在互聯網上生存的最長時間,超過這個時間將在網絡中消失。MSL在RFC 1122上建議是2分鐘,而源自berkeley的TCP實現傳統上使用30秒,於是,TIME_WAIT狀態通常維持在1-4分鐘。
1)可靠地實現TCP全雙工鏈接的終止
在進行關閉鏈接四路握手協議時,最後的ACK是由主動關閉端發出的,若是這個最終的ACK丟失,服務器將重發最終的FIN,所以客戶端必須維護狀態信息允 許它重發最終的ACK。若是不維持這個狀態信息,那麼客戶端將響應RST分節,服務器將此分節解釋成一個錯誤(在java中會拋出connection reset的SocketException)。於是,要實現TCP全雙工鏈接的正常終止,必須處理終止序列四個分節中任何一個分節的丟失狀況,主動關閉 的客戶端必須維持狀態信息進入TIME_WAIT狀態。
2)容許老的重複分節在網絡中消逝
TCP分節可能因爲路由器異常而「迷途」,在迷途期間,TCP發送端可能因確認超時而重發這個分節,迷途的分節在路由器修復後也會被送到最終目的地,這個 原來的迷途分節就稱爲lost duplicate。在關閉一個TCP鏈接後,立刻又從新創建起一個相同的IP地址和端口之間的TCP鏈接,後一個鏈接被稱爲前一個鏈接的化身 (incarnation),那麼有可能出現這種狀況,前一個鏈接的迷途重複分組在前一個鏈接終止後出現,從而被誤解成從屬於新的化身。爲了不這個情 況,TCP不容許處於TIME_WAIT狀態的鏈接啓動一個新的化身,由於TIME_WAIT狀態持續2MSL,就能夠保證當成功創建一個TCP鏈接的時 候,來自鏈接先前化身的重複分組已經在網絡中消逝。
本博客文章除特別聲明,所有都是原創!
尊重原創,轉載請註明: 轉載自過往記憶(http://www.iteblog.com/)
本文連接地址: 《TCP/IP狀態圖的TIME_WAIT做用》(http://www.iteblog.com/archives/169)
參考:http://www.cricode.com/3568.html
========END========