【網絡協議】TCP連接的建立和釋放

轉載請註明出處:http://blog.csdn.net/ns_code/article/details/29382883

TCP首部格式

    先看TCP報文段的格式,如下;

    TCP報文段首部的前20個字節是固定的,後面有4N字節是根據需要而增加的選項。因此TCP報文段的最小長度爲20個字節。

    首部固定部分的各字段的意義如下:

    1、源端口和目的端口:加上IP首部的源IP地址和目的IP地址,確定唯一的一個TCP連接。另外通過目的端口來決定TCP將數據報交付於那個應用程序,從而實現TCP的分用功能。

    2、序號:佔4個字節,序號的範圍爲[0,4284967296]。由於TCP是面向字節流的,在一個TCP連接中傳送的字節流中的每一個字節都按順序編號,首部中的序號字段則是指本報文段所發送的數據的第一個字節的序號。另外,序號是循環使用的,當序號增加到最大值時,下一個序號就又回到了0。

    3、確認號:當ACK標誌位爲1時有效,表示期望收到的下一個報文段的第一個數據字節的序號。確認號爲N,則表明到序號N-1爲止的所有數據字節都已經被正確地接收到了。

    4、頭部長度:TCP報文段的頭部長度,它指出TCP報文段的數據部分的起始位置與TCP報文段的起始位置的距離。頭部長度佔4個字節,但它的單位是32位字,即以4字節爲計算單位,因此頭部長度的最大值爲15*4=60個字節,這就意味着選項的長度不超過40個字節。

    5、保留位:必須爲0.

    6、下面的六個控制位說明報文段的性質:

    1)URG:與首部中的緊急指針字段配合使用。URG爲1時,表明緊急指針字段有效,發送應用進程告訴發送方的TCP有緊急數據要傳送,於是發送方TCP就把緊急數據插入到本報文段數據的最前面,而其後面仍是普通數據。

    2)ACK:僅當ACK=1時確認號字段纔有效,當ACK=0時,確認號無效。TCP規定,在連接建立後所有的傳送報文段都必須把ACK置1。

    3)PSH:如果發送的報文段中PSH爲1,則接收方接受到該報文段後,直接將其交付給應用進程,而不再等待整個緩存都填滿後再向上交付。

    4)RST:復位標誌,RST=1時,表明TCP連接中出現嚴重差錯,必須釋放連接,然後重新建立運輸連接。

    5)SYN:同步序號,用來發起一個連接。當SYN=1而ACK=0時,表明這是一個連接請求報文段,若對方同意建立連接,則應在響應的報文段中使SYN=1和ACK=1。

    6)FIN:用來釋放一個連接。當FIN=1時,表明此報文段的發送方的數據已發送完畢,並要求釋放連接。

    7、窗口:接收方讓發送方下次發送報文段時設置的發送窗口的大小。

    8、校驗和:校驗的字段範圍包括首部和數據這兩部分。

    9、緊急指針:緊急指針當URG=1時纔有效,它指出本報文段中的緊急數據的字節數。值得注意的是,即使窗口爲0時,也可發送緊急數據。

    10、選項與填充:選項應該爲4字節的整數倍,否則用0填充。最常見的可選字段是最長報文大小MSS(Maximum Segment Size),每個連接方通常都在通信的第一個報文段中指明這個選項。它指明本端所能接收的最大長度的報文段。該選項如果不設置,默認爲536(20+20+536=576字節的IP數據報),其中ip首部和tcp首部各20個字節,而internet 上標準的MTU (最小)爲576B。  

TCP連接的建立

下圖爲TCP三次握手連接的建立過程:

    服務端的TCP進程先創建傳輸控制塊TCB,準備接受客戶端進程的連接請求,然後服務端進程處於LISTEN狀態,等待客戶端的連接請求,如有,則作出響應。

    1、客戶端的TCP進程也首先創建傳輸控制模塊TCB,然後向服務端發出連接請求報文段,該報文段首部中的SYN=1,ACK=0,同時選擇一個初始序號seq=i。TCP規定,SYN=1的報文段不能攜帶數據,但要消耗掉一個序號。這時,TCP客戶進程進入SYN—SENT(同步已發送)狀態,這是TCP連接的第一次握手。

    2、服務端收到客戶端發來的請求報文後,如果同意建立連接,則向客戶端發送確認。確認報文中的SYN=1,ACK=1,確認號ack=i+1,同時爲自己選擇一個初始序號seq=j。同樣該報文段也是SYN=1的報文段,不能攜帶數據,但同樣要消耗掉一個序號。這時,TCP服務端進入SYN—RCVD(同步收到)狀態,這是TCP連接的第二次握手。

    3、TCP客戶端進程收到服務端進程的確認後,還要向服務端給出確認。確認報文段的ACK=1,確認號ack=j+1,而自己的序號爲seq=i+1。TCP的標準規定,ACK報文段可以攜帶數據,但如果不攜帶數據則不消耗序號,因此,如果不攜帶數據,則下一個報文段的序號仍爲seq=i+1。這時,TCP連接已經建立,客戶端進入ESTABLISHED(已建立連接)狀態。這是TCP連接的第三次握手,可以看出第三次握手客戶端已經可以發送攜帶數據的報文段了。

    當服務端收到確認後,也進入ESTABLISHED(已建立連接)狀態。

雙方同時主動連接的TCP連接建立過程     正常情況下,傳輸連接都是由一方主動發起的,但也有可能雙方同時主動發起連接,此時就會發生連接碰撞,最終只有一個連接能夠建立起來。因爲所有連接都是由它們的端點進行標識的。如果第一個連接請求建立起一個由套接字(x,y)標識的連接,而第二個連接也建立了這樣一個連接,那麼在TCP實體內部只有一個套接字表項。 當出現同時發出連接請求時,則兩端幾乎在同時發送一個SYN字段置1的數據段,並進入SYN_SENT狀態。當每一端收到SYN數據段時,狀態變爲SYN_RCVD,同時它們都再發送SYN字段置1,ACK字段置1的數據段,對收到的SYN數據段進行確認。當雙方都收到對方的SYN+ACK數據段後,便都進入ESTABLISHED狀態。圖10-39顯示了這種同時發起連接的連接過程,但最終建立的是一個TCP連接,而不是兩個,這點要特別注意。

    從圖中可以看出,一個雙方同時打開的傳輸連接需要交換4數據段,比正常的傳輸連接建立所進行的三次握手多交換一個數據段。此外要注意的是,此時我們沒有將任何一端稱爲客戶或服務器,因爲每一端既是客戶又是服務器。

爲什麼一定要進行三次握手呢?

    前兩次的握手很顯然是必須的,主要是最後一次,即客戶端收到服務端發來的確認後爲什麼還要想服務端再發送一次確認呢?這主要是爲了防止已失效的請求報文段突然又傳送到了服務端而產生連接的誤判。

    考慮如下的情況:客戶端發送了一個連接請求報文段到服務端,但是在某些網絡節點上長時間滯留了,而後客戶端又超時重發了一個連接請求報文段該服務端,而後正常建立連接,數據傳輸完畢,並釋放了連接。如果這時候第一次發送的請求報文段延遲了一段時間後,又到了服務端,很顯然,這本是一個早已失效的報文段,但是服務端收到後會誤以爲客戶端又發出了一次連接請求,於是向客戶端發出確認報文段,並同意建立連接。假設不採用三次握手,這時服務端只要發送了確認,新的連接就建立了,但由於客戶端比你更沒有發出建立連接的請求,因此不會理會服務端的確認,也不會向服務端發送數據,而服務端卻認爲新的連接已經建立了,並在一直等待客戶端發送數據,這樣服務端就會一直等待下去,直到超出保活計數器的設定值,而將客戶端判定爲出了問題,纔會關閉這個連接。這樣就浪費了很多服務器的資源。而如果採用三次握手,客戶端就不會向服務端發出確認,服務端由於收不到確認,就知道客戶端沒有要求建立連接,從而不建立該連接。

TCP連接的釋放

下圖爲TCP四次揮手的釋放過程:

    數據傳輸結束後,通信的雙方都可以釋放連接,並停止發送數據。假設現在客戶端和服務端都處於ESTABLISHED狀態。

    1、客戶端A的TCP進程先向服務端發出連接釋放報文段,並停止發送數據,主動關閉TCP連接。釋放連接報文段中FIN=1,序號爲seq=u,該序號等於前面已經傳送過去的數據的最後一個字節的序號加1。這時,A進入FIN—WAIT-1(終止等待1)狀態,等待B的確認。TCP規定,FIN報文段即使不攜帶數據,也要消耗掉一個序號。這是TCP連接釋放的第一次揮手。

    2、B收到連接釋放報文段後即發出確認釋放連接的報文段,該報文段中,ACK=1,確認號爲ack=u+1,其自己的序號爲v,該序號等於B前面已經傳送過的數據的最後一個字節的序號加1。然後B進入CLOSE—WAIT(關閉等待)狀態,此時TCP服務器進程應該通知上層的應用進程,因而A到B這個方向的連接就釋放了,這時TCP處於半關閉狀態,即A已經沒有數據要發了,但B若發送數據,A仍要接受,也就是說從B到A這個方向的連接並沒有關閉,這個狀態可能會持續一些時間。這是TCP連接釋放的第二次揮手。

    3、A收到B的確認後,就進入了FIN—WAIT(終止等待2)狀態,等待B發出連接釋放報文段,如果B已經沒有要向A發送的數據了,其應用進程就通知TCP釋放連接。這時B發出的鏈接釋放報文段中,FIN=1,確認號還必須重複上次已發送過的確認號,即ack=u+1,序號seq=w,因爲在半關閉狀態B可能又發送了一些數據,因此該序號爲半關閉狀態發送的數據的最後一個字節的序號加1。這時B進入LAST—ACK(最後確認)狀態,等待A的確認,這是TCP連接的第三次揮手。

    4、A收到B的連接釋放請求後,必須對此發出確認。確認報文段中,ACK=1,確認號ack=w+1,而自己的序號seq=u+1,而後進入TIME—WAIT(時間等待)狀態。這時候,TCP連接還沒有釋放掉,必須經過時間等待計時器設置的時間2MSL後,A才進入CLOSED狀態,時間MSL叫做最長報文壽命,RFC建議設爲2分鐘,因此從A進入TIME—WAIT狀態後,要經過4分鐘才能進入到CLOSED狀態,而B只要收到了A的確認後,就進入了CLOSED狀態。二者都進入CLOSED狀態後,連接就完全釋放了,這是TCP連接的第四次揮手。

    雙方主動關閉的TCP連接釋放流程

    與可以雙方同時建立TCP傳輸連接一樣,TCP傳輸連接關閉也可以由雙方同時主動進行(正常情況下都是由一方發送第一個FIN數據段進行主動連接關閉,另一方被動接受連接關閉)

    當兩端對應的網絡應用層進程同時調用CLOSE原語,發送FIN數據段執行關閉命令時,兩端均從ESTABLISHED狀態轉變爲FIN WAIT 1狀態。任意一方收到對端發來的FIN數據段後,其狀態均由FIN WAIT 1轉變到CLOSING狀態,併發送最後的ACK數據段。當收到最後的ACK數據段後,狀態轉變化TIME_WAIT,在等待2MSL後進入到CLOSED狀態,最終釋放整個TCP傳輸連接。

    爲什麼A在TIME—WAIT狀態必須等待2MSL時間呢?

    1、爲了保證A發送的最後一個ACK報文段能夠到達B。該ACK報文段很有可能丟失,因而使處於在LIST—ACK狀態的B收不到對已發送的FIN+ACK報文段的確認,B可能會重傳這個FIN+ACK報文段,而A就在這2MSL時間內收到這個重傳的FIN+ACK報文段,接着A重傳一次確認,重新啓動2MSL計時器,最後A和B都進入CLOSED狀態。如果A在TIME—WAIT狀態不等待一段時間就直接釋放連接,到CLOSED狀態,那麼久無法收到B重傳的FIN+ACK報文段,也就不會再發送一次確認ACK報文段,B就無法正常進入CLOSED狀態。

    2、防止已失效的請求連接出現在本連接中。在連接處於2MSL等待時,任何遲到的報文段將被丟棄,因爲處於2MSL等待的、由該插口(插口是IP和端口對的意思,socket)定義的連接在這段時間內將不能被再用,這樣就可以使下一個新的連接中不會出現這種舊的連接之前延遲的報文段。

    補充:

    當客戶端執行主動關閉並進入TIME—WAIT是正常的,服務端執行被動關閉,不會進入TIME—WAIT狀態,這說明,如果終止了一個客戶程序,並立即重啓該客戶程序,則新的客戶程序將不再重用相同的本地端口,而是使用新的端口,這不會帶來什麼問題,因爲客戶端使用本地端口,而並不關心這個端口是多少。但對於服務器來說,情況就不同了,服務器總是用我們熟知的端口,那麼在2MSL時間內,重啓服務器就會出錯,爲了避免這個錯誤,服務器給出了一個平靜時間的概念,這是說在2MSL時間內,雖然可以重新啓動服務器,但是這個服務器還是要平靜的等待2MSL時間的過去才能進行下一次連接。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章