TCP 狀態詳解 -轉載

TCP 是一個面向鏈接的協議,不管哪一方向另外一方發送數據以前,都必須先在雙方之間創建一條鏈接。本節將詳細討論一個TCP 鏈接是如何創建的以及通訊結束後是如何終止的。服務器

創建一個 TCP 鏈接
  TCP使用三次握手 ( three-way handshake ) 協議來創建鏈接,圖 3-10 描述了三次握手的報文序列。
www.2cto.com

這三次握手爲:
請求端(一般稱爲客戶)發送一個 SYN 報文段( SYN 爲 1 )指明客戶打算鏈接的服務器的端口,以及初始順序號( ISN )。
服務器發回包含服務器的初始順序號的 SYN 報文段( SYN 爲 1 )做爲應答。同時,將確認號設置爲客戶的 ISN 加 1 以對客戶的 SYN 報文段進行確認( ACK 也爲 1 )。
客戶必須將確認號設置爲服務器的 ISN 加 1 以對服務器的 SYN 報文段進行確認( ACK 爲 1 ),該報文通知目的主機雙方已完成鏈接創建。
 
發送第一個 SYN 的一端將執行主動打開( active open ),接收這個 SYN 併發回下一個 SYN 的另外一端執行被動打開( passive open )。另外, TCP 的握手協議被精心設計爲能夠處理同時打開( simultaneous open ),對於同時打開它僅創建一條鏈接而不是兩條鏈接。所以,鏈接能夠由任一方或雙方發起,一旦鏈接創建,數據就能夠雙向對等地流動,而沒有所謂的主從關係。
www.2cto.com
 
  三次握手協議是鏈接兩端正確同步的充要條件。由於 TCP 創建在不可靠的分組傳輸服務之上,報文可能丟失、延遲、重複和亂序,所以協議必須使用超時和重傳機制。若是重傳的鏈接請求和原先的鏈接請求在鏈接正在創建時到達,或者當一個鏈接已經創建、使用和結束以後,某個延遲的鏈接請求才到達,就會出現問題。採用三次握手協議(加上這樣的規則:在鏈接創建以後 TCP 就再也不理睬又一次的鏈接請求)就能夠解決這些問題。
 
  三次握手協議能夠完成兩個重要功能:它確保鏈接雙方作好傳輸準備,並使雙方統一了初始順序號。初始順序號是在握手期間傳輸順序號並得到確認:當一端爲創建鏈接而發送它的 SYN 時,它爲鏈接選擇一個初始順序號;每一個報文段都包括了順序號字段和確認號字段,這使得兩臺機器僅僅使用三個握手報文就能協商好各自的數據流的順序號。通常來講, ISN 隨時間而變化,所以每一個鏈接都將具備不一樣的 ISN 。www.2cto.com
 
關閉一個 TCP 鏈接
  TCP 鏈接創建起來後,就能夠在兩個方向傳送數據流。當 TCP 的應用進程再沒有數據須要發送時,就發關閉命令。 TCP 經過發送控制位 FIN=1 的數據片來關閉本方數據流,但還能夠繼續接收數據,直到對方關閉那個方向的數據流,鏈接就關閉。
 
  TCP 協議使用修改的三次握手協議來關閉鏈接, 如圖 3-11 所示,即終止一個鏈接要通過 4 次握手。這是由於 TCP 的半關閉( half-close )形成的。因爲一個 TCP 鏈接是全雙工(即數據在兩個方向上能同時傳遞),所以每一個方向必須單獨地進行關閉。關閉的原則就是當一方完成它的數據發送任務後就能發送一個 FIN 來終止這個方向鏈接。當一端收到一個 FIN ,它必須通知應用層另外一端已經終止了那個方向的數據傳送。發送 FIN 一般是應用層進行關閉的結果。
 
從一方的 TCP 來講,鏈接的關閉有三種狀況:www.2cto.com   、
• 本方啓動關閉
  收到本方應用進程的關閉命令後, TCP 在發送完還沒有處理的報文段後,發 FIN = 1 的報文段給對方,且 TCP 再也不受理本方應用進程的數據發送。在 FIN 之前發送的數據字節,包括 FIN ,都須要對方確認,不然要重傳。注意 FIN 也佔一個順序號。一旦收到對方對 FIN 的確認以及對方的 FIN 報文段,本方 TCP 就對該 FIN 進行確認,在等待一段時間,而後關閉鏈接。等待是爲了防止本方的確認報文丟失,避免對方的重傳報文干擾新的鏈接。
 
  • 對方啓動關閉
  當 TCP 收到對方發來的 FIN 報文時,發 ACK 確認此 FIN 報文,並通知應用進程鏈接正在關閉。應用進程將以關閉命令響 應。 TCP 在發送完還沒有處理的報文段後,發一個 FIN 報文給對方 TCP ,而後等待對方對 FIN 的確認,收到確認後關閉鏈接。若對方的確認未及時到達,在等待一段時間後也關閉鏈接。
  • 雙方同時啓動關閉
  鏈接雙方的應用進程同時發關閉命令,則雙方 TCP 在發送完還沒有處理的報文段後,發送 FIN 報文。各方 TCP 在 FIN 前所發報文都獲得確認後,發 ACK 確認它收到的 FIN 。各方在收到對方對 FIN 的確認後,一樣等待一段時間再關閉鏈接。這稱之爲同時關閉( simultaneous close )。www.2cto.com
 
TCP 狀態機
  TCP 協議的操做可使用一個具備 11 種狀態的有限狀態機( Finite State Machine )來表示,圖 3-12 描述了 TCP 的有限狀態機,圖中的圓角矩形表示狀態,箭頭表示狀態之間的轉換,各狀態的描述如表 3-2 所示。圖中用粗線表示客戶端主動和被動的服務器端創建鏈接的正常過程:客戶端的狀態變遷用粗實線,服務器端的狀態變遷用粗虛線。細線用於不常見的序列,如復位、同時打開、同時關閉等。圖中的每條狀態變換線上均標有「事件/動做」:事件是指用戶執行了系統調用( CONNECT 、 LISTEN 、 SEND 或 CLOSE )、收到一個報文段( SYN 、 FIN 、 ACK 或 RST )、或者是出現了超過兩倍最大的分組生命期的狀況;動做是指發送一個報文段( SYN 、 FIN 或 ACK )或什麼也沒有(用「-」表示)。
 
圖 3-12 TCP 有限狀態機。粗實線表示客戶的正常路徑;
粗虛線表示服務器的正常路徑;細線表示不常見的事件。
  每一個鏈接均開始於 CLOSED 狀態。當一方執行了被動的鏈接原語( LISTEN )或主動的鏈接原語( CONNECT )時,它便會脫離 CLOSED 狀態。若是此時另外一方執行了相對應的鏈接原語,鏈接便創建了,而且狀態變爲 ESTABLISHED 。任何一方都可以首先請求釋放鏈接,當鏈接被釋放後,狀態又回到了 CLOSED 。
表 3-2 TCP 狀態表
 
1. 正常狀態轉換
  咱們用圖 3-13 來顯示在正常的 TCP 鏈接的創建與終止過程當中,客戶與服務器所經歷的不一樣狀態。讀者能夠對照圖 3-12 來 閱讀,使用圖 3-12 的狀態圖來跟蹤圖 3-13 的狀態變化過程,以便明白每一個狀態的變化:
服務器端首先執行 LISTEN 原語進入被動打開狀態( LISTEN ),等待客戶端鏈接;www.2cto.com
當客戶端的一個應用程序發出 CONNECT 命令後,本地的 TCP 實體爲其建立一個鏈接記錄並標記爲 SYN SENT 狀態,而後給服務器發送一個 SYN 報文段;
 
服務器收到一個 SYN 報文段,其 TCP 實體給客戶端發送確認 ACK 報文段同時發送一個 SYN 信號,進入 SYN RCVD 狀態;
客戶端收到 SYN + ACK 報文段,其 TCP 實體給服務器端發送出三次握手的最後一個 ACK 報文段,並轉換爲 ESTABLISHED 狀態;
服務器端收到確認的 ACK 報文段,完成了三次握手,因而也進入 ESTABLISHED 狀態。
   在此狀態下,雙方能夠自由傳輸數據。當一個應用程序完成數據傳輸任務後,它須要關閉 TCP 鏈接。假設仍由客戶端發起主動關閉鏈接。
客戶端執行 CLOSE 原語,本地的 TCP 實體發送一個 FIN 報文段並等待響應的確認(進入狀態 FIN WAIT 1 );
服務器收到一個 FIN 報文段,它確認客戶端的請求發回一個 ACK 報文段,進入 CLOSE WAIT 狀態;
客戶端收到確認 ACK 報文段,就轉移到 FIN WAIT 2 狀態,此時鏈接在一個方向上就斷開了;
服務器端應用獲得通告後,也執行 CLOSE 原語關閉另外一個方向的鏈接,其本地 TCP 實體向客戶端發送一個 FIN 報文段,並進入 LAST ACK 狀態,等待最後一個 ACK 確認報文段;www.2cto.com
 
客戶端收到 FIN 報文段並確認,進入 TIMED WAIT 狀態,此時雙方鏈接均已經斷開,但 TCP 要等待一個 2 倍報文段最大生存時間 MSL ( Maximum Segment Lifetime ),確保該鏈接的全部分組所有消失,以防止出現確認丟失的狀況。當定時器超時後, TCP 刪除該鏈接記錄,返回到初始狀態( CLOSED )。
服務器收到最後一個確認 ACK 報文段,其 TCP 實體便釋放該鏈接,並刪除鏈接記錄,返回到初始狀態( CLOSED )。
2. 同時打開:
  儘管發生的可能性極小,兩個應用程序同時彼此執行主動打開的狀況仍是可能的。每一方必須發送一個 SYN ,且這些 SYN 必須傳遞給對方。這須要每一方使用一個對方周知的端口做爲本地端口。例如,主機 A 中的一個應用程序使用本地端口 7777 ,並與主機 B 的端口 8888 執行主動打開。主機 B 中的應用程序則使用本地端口 8888 ,並與主機 A 的端口 7777 執行主動打開。 TCP 是特地設計爲了能夠處理同時打開,對於同時打開它僅創建一條鏈接而不是兩條鏈接(其餘的協議族,最突出的是 OSI 傳輸層,在這種狀況下將創建兩條鏈接而不是一條鏈接)。www.2cto.com
 
  當出現同時打開的狀況時,狀態變遷與圖 3-13 所示的不一樣。兩端幾乎在同時發送 SYN ,並進入 SYN_SENT 狀態。當每一端收到 SYN 時,狀態變爲 SYN_RCVD ,同時它們都再發 SYN 並對收到的 SYN 進行確認。當雙方都收到 SYN 及相應的 ACK 時,狀態都變遷爲 ESTABLISHED 。圖 3-14 顯示了這些狀態變遷過程。
圖 3-14 同時打開期間報文段的交換
 
  一個同時打開的鏈接須要交換 4 個報文段,比正常的三次握手多一個。此外,要注意的是咱們沒有將任何一端稱爲客戶或服務器,由於每一端既是客戶又是服務器。
3. 同時關閉:
  正常狀況下都是由一方(一般但不老是客戶方)發送第一個 FIN 執行主動關閉,但雙方都執行主動關閉也是可能的, TCP 協議也容許這樣的同時關閉。www.2cto.com
 
  在圖 3-12 中,當兩端應用層同時發出關閉命令時,兩端均從 ESTABLISHED 變爲 FIN_WAIT_1 。這將致使雙方各發送一個 FIN ,兩個 FIN 通過網絡傳送後分別到達另外一端。收到 FIN 後,狀態由 FIN_WAIT_1 變遷到 CLOSING ,併發送最後的 ACK 。當收到最後的 ACK 時,狀態變化爲 TIME_WAIT 。圖 3-15 總結了這些狀態的變化,從圖中能夠看出同時關閉與正常關閉使用的報文段交換數目相同。
圖 3-15 同時關閉期間的報文段交換
4. 其它狀況:
服務方打開:從 LISTEN 到 SYN_SENT 的變遷是正確的,它由服務器端主動發出 SYN 報文段,但 Berkeley 版的 TCP 軟件並不支持它。
重置鏈接(復位):只有當 SYN_RCVD 狀態是從 LISTEN 狀態(正常狀況)進入,而不是從 SYN_SENT 狀態(同時打開)進入時,從 SYN_RCVD 回到 LISTEN 的狀態變遷纔是有效的。這意味着若是咱們執行被動打開(進入 LISTEN ),收到一個 SYN ,發送一個帶 ACK 的 SYN (進入 SYN_RCVD ),而後收到一個 RST ,而不是一個 ACK ,便又回到 LISTEN 狀態並等待另外一個鏈接請求的到來。www.2cto.com
 
快速關閉:在主動關閉後的 FIN_WAIT_1 狀態,若是收到的報文段不只是 ACK ,並且還包括對方的 FIN 信號,則直接進入 TIME_WAIT 狀態,給對方發送 ACK 報文段,而後等待超時。
  另外, TIME_WAIT 狀態的等待超時須要再詳細解釋一下,由於它直接影響到網絡應用程序的表現。
  每一個具體 TCP 實現必須選擇一個報文段最大生存時間 MSL ( Maximum Segment Lifetime ),它是任何報文段被丟棄前在網絡內的最長時間。咱們知道這個時間是有限的,由於 TCP 報文段以 IP 數據報在網絡內傳輸,而 IP 數據報有限制其生存時間的 TTL 字段。 RFC 793 [Postel 1981c ] 指出 MSL 爲 2 分鐘。然而,實現中的經常使用值是 30 秒、 1 分鐘、或 2 分鐘。
 
  對一個具體實現所給定的 MSL 值,處理的原則是:當 TCP 執行一個主動關閉,併發回最後一個 ACK ,該鏈接必須在 TIME_WAIT 狀態停留的時間爲 2 倍的 MSL ,所以 TIME_WAIT 狀態也稱爲 2MSL 等待狀態。在這段時間內,若是最後的 ACK 丟失,對方會超時並重發最後的 FIN ,這樣本地 TCP 能夠再次發送 ACK 報文段(這也是它惟一能夠發送的報文,並重置 2MSL 定時器)。
 
  這種 2MSL 等待的另外一個結果是這個 TCP 鏈接在 2MSL 等待期間,定義這個鏈接的套接字( socket ,客戶的 IP 地址和端口號,服務器的 IP 地址和端口號)不能再被使用。這個鏈接只能在 2MSL 結束後才能再被使用。在鏈接處於 2MSL 等待時,任何遲到的報文段將被丟棄。www.2cto.com
 
  咱們假設圖 3-12 中是客戶執行主動關閉並進入 TIME_WAIT ,這是正常的狀況,由於服務器一般執行被動關閉,不會進入 TIME_WAIT 狀態。這暗示若是咱們終止一個客戶程序,並當即從新啓動這個客戶程序,則這個新客戶程序將不能重用相同的本地端口。這不會帶來什麼問題,由於客戶使用本地端口,而並不關心這個端口號是什麼。然而,對於服務器,狀況就有所不一樣,由於服務器使用周知端口。 若是咱們終止一個已經創建鏈接的服務器程序,並試圖當即從新啓動這個服務器程序,服務器程序將不能把它的這個周知端口賦值給它的端點,由於那個端口是處於 2MSL 鏈接的一部分。在從新啓動服務器程序前,它須要在 1~4 分鐘。這就是不少網絡服務器程序被殺死後不可以立刻從新啓動的緣由(錯誤提示爲「 Address already in use 」)。
相關文章
相關標籤/搜索