Linux下TCP串連過程總結

來源:互聯網
上載者:User

一、Linux伺服器上11種網路連接狀態:


      圖:TCP的狀態機器

通常情況下,一個正常的TCP串連,都會有三個階段:1、TCP三向交握; 2、資料傳送; 3、TCP四次揮手

注:以下說明最好能結合”圖:TCP的狀態機器”來理解。

SYN: (同步序列編號,Synchronize Sequence Numbers)該標誌僅在三向交握建立TCP串連時有效。表示一個新的TCP串連請求。

ACK: (確認編號,Acknowledgement Number)是對TCP請求的確認標誌,同時提示對端系統已經成功接收所有資料。

FIN: (結束標誌,FINish)用來結束一個TCP回話.但對應連接埠仍處於開放狀態,準備接收後續資料。

1)、LISTEN:首先服務端需要開啟一個socket進行監聽,狀態為LISTEN. /* The socket is listening for incoming connections. 偵聽來自遠方TCP連接埠的串連請求 */
2)、SYN_SENT:用戶端通過應用程式調用connect進行active open.於是用戶端tcp發送一個SYN以請求建立一個串連.之後狀態置為SYN_SENT. /*The socket is actively attempting to establish a connection. 在發送串連請求後等待匹配的串連請求 */

3)、SYN_RECV:服務端應發出ACK確認用戶端的SYN,同時自己向用戶端發送一個SYN. 之後狀態置為SYN_RECV /* A connection request has been received from the network. 在收到和發送一個串連請求後等待對串連請求的確認 */

4)、ESTABLISHED: 代表一個開啟的串連,雙方可以進行或已經在資料互動了。/* The socket has an established connection. 代表一個開啟的串連,資料可以傳送給使用者 */

5)、FIN_WAIT1:主動關閉(active close)端應用程式調用close,於是其TCP發出FIN請求主動關閉串連,之後進入FIN_WAIT1狀態./* The socket is closed, and the connection is shutting down. 等待遠程TCP的串連插斷要求,或先前的串連插斷要求的確認 */

6)、CLOSE_WAIT:被動關閉(passive close)端TCP接到FIN後,就發出ACK以回應FIN請求(它的接收也作為檔案結束符傳遞給上層應用程式),並進入CLOSE_WAIT. /* The remote end has shut down, waiting for the socket to close. 等待從本機使用者發來的串連插斷要求 */

7)、FIN_WAIT2:主動關閉端接到ACK後,就進入了FIN-WAIT-2 ./* Connection is closed, and the socket is waiting for a shutdown from the remote end. 從遠程TCP等待串連插斷要求 */

8)、LAST_ACK:被動關閉端一段時間後,接收到檔案結束符的應用程式將調用CLOSE關閉串連。這導致它的TCP也發送一個 FIN,等待對方的ACK.就進入了LAST-ACK . /* The remote end has shut down, and the socket is closed. Waiting for acknowledgement. 等待原來發向遠程TCP的串連插斷要求的確認 */

9)、TIME_WAIT:在主動關閉端接收到FIN後,TCP就發送ACK包,並進入TIME-WAIT狀態。/* The socket is waiting after close to handle packets still in the network.等待足夠的時間以確保遠程TCP接收到串連插斷要求的確認 */

10)、CLOSING: 比較少見./* Both sockets are shut down but we still don’t have all our data sent. 等待遠程TCP對串連中斷的確認 */

11)、CLOSED: 被動關閉端在接受到ACK包後,就進入了closed的狀態。串連結束./* The socket is not being used. 沒有任何串連狀態 */
TIME_WAIT狀態的形成只發生在主動關閉串連的一方。
 
 主動關閉方在接收到被動關閉方的FIN請求後,發送成功給對方一個ACK後,將自己的狀態由FIN_WAIT2修改為TIME_WAIT,而必須再等2
倍 的MSL(Maximum Segment
Lifetime,MSL是一個資料報在internetwork中能存在的時間)時間之後雙方才能把狀態
都改為CLOSED以關閉串連。目前RHEL裡保持TIME_WAIT狀態的時間為60秒。當然上述很多TCP狀態在系統裡都有對應的解釋或設定,可見
man tcp

二、關於長串連和短串連:
  通俗點講,短串連就是一次TCP請求得到結果後,串連馬上結束.而長串連並不馬上斷開,而一直保持著,直到長串連TIMEOUT(具體程式都有相關參數說明).長串連可以避免不斷的進行TCP三向交握和四次揮手.

串連(keepalive)是需要靠雙方不斷的發送探測包來維持的,keepalive期間服務端和用戶端的TCP串連狀態是ESTABLISHED.目
前http 1.1版本裡預設都是keepalive(1.0版本預設是不keepalive的),ie6/7/8和firefox都預設用的是http
1.1版本了(如何查看當前瀏覽器用的是哪個版本,這裡不再贅述)。Apache,java

  一個應用至於到底是該使用短串連還是長串連,應該視具體情況而定。一般的應用應該使用長串連。

tcp 四次揮手

 
 TCP協議有一個優雅的關閉(graceful
close)機制,以保證應用程式在關閉串連時不必擔心正在傳輸的資料會丟失。如第4.5節的壓縮樣本程式所示,這個機制還設計為允許兩個方向的資料轉送
相互獨立地終止。關閉機制的工作流程是:應用程式通過調用串連通訊端的close()方法或shutdownOutput()方法表明資料已經發送完畢。
此刻,底層的TCP實現首先將留存在SendQ隊列中的資料轉送出去(還要依賴於另一端RecvQ隊列的剩餘空間),然後向另一端發送一個關閉TCP串連
的握手訊息。該關閉握手訊息可以看作是流終止標誌:它告訴接收端TCP不會再有新的資料傳入RecvQ隊列了。(注意,關閉握手訊息本身並沒有傳遞給接收
端應用程式,而是通過read()方法返回-1來指示其在位元組流中的位置。)正在關閉的TCP將等待其關閉握手訊息的確認資訊,該確認資訊表明在串連上傳
輸的所有資料已經安全地傳輸到了RecvQ中。只要收到了確認訊息,該串連就變成"半關閉(Half
closed)"狀態。直到串連的另一個方向上收到了對稱的握手訊息後,串連才完全關閉--也就是說,串連的兩端都表明它們再沒有資料要發送了。

 
 TCP串連的關閉事件序列可能以兩種方式發生:一種方式是先由一個應用程式調用close()方法(或shutdownOutput()方法),並在另
一端調用close()方法之前完成其關閉握手訊息;另一種方式是兩端同時調用close()方法,它們的關閉握手訊息在網路上交叉傳輸。圖6.10展示
了以第一種方式關閉串連時,底層實現中的事件序列。關閉握手訊息已經發送,通訊端資料結構的狀態也已經設定為"Closing"(專業術語稱
為"FIN_WAIT_1"),然後close()調用返回。完成這些工作後,將禁止在該Socket上的任何讀寫操作(會拋出異常)。當收到關閉握手確
認訊息後,通訊端資料結構的狀態則改變為"半關閉"(專業術語稱為"FIN_WAIT_2"),這種狀態將一直持續,直到接收到另一端的關閉握手訊息

 
 關閉TCP串連的最後微妙之處在於對Time-Wait狀態的需要。TCP規範要求在終止串連時,兩端的關閉握手都完成後,至少要有一個通訊端在
Time-Wait狀態保持一段時間。這個要求的提出是由於訊息在網路中傳輸時可能延遲。如果在串連兩端都完成了關閉握手後,它們都移除了其底層資料結
構,而此時在同樣一對通訊端地址之間又立即建立了新的串連,那麼前一個串連在網路上傳輸時延遲的訊息就可能在新串連建立後到達。由於其包含了相同的源地址
和目的地址,舊訊息就會被錯誤地認為是屬於新串連的,其包含的資料就可能被錯誤地分配到應用程式中。

 
 雖然這種情形可能很少發生,TCP還是使用了包括Time-Wait狀態在內的多種機制對其進行防範。Time-Wait狀態用於保證每個TCP串連都
在一段平靜時間內結束,這期間不會有資料發送。平靜時間的長度應該等於分組報文在網路上存留的最長時間的兩倍。因此,當一個串連完全結束(即通訊端資料結
構離開Time-Wait狀態並被刪除),並為同樣一對地址上的新串連清理道路後,就不會再有舊執行個體發送的訊息還存留在網路中。實際上,平靜時間的長度要
依賴於具體實現,因為沒有機制能真正限制分組報文在網路上能夠延遲的時間。通常使用的時間範圍是4分鐘減到30秒,或更短。

  Time-Wait狀態最重要的作用是,只要底層通訊端資料結構還存在,就不允許在相同的本地連接埠上關聯其他通訊端。尤其是試圖使用該連接埠建立新的Socket執行個體時,將拋出IOException異常。

 

TCP三向交握/四次揮手詳解

1、建立連線協定(三向交握)
(1)用戶端發送一個帶SYN標誌的TCP報文到伺服器。這是三向交握過程中的報文1。
(2) 伺服器端回應用戶端的,這是三向交握中的第2個報文,這個報文同時帶ACK標誌和SYN標誌。因此它表示對剛才用戶端SYN報文的回應;同時又標誌SYN給用戶端,詢問用戶端是否準備好進行資料通訊。
(3) 客戶必須再次回應服務段一個ACK報文,這是報文段3。

2、串連終止協議(四次揮手)
 

 由於TCP串連是全雙工系統的,因此每個方向都必須單獨進行關閉。這原則是當一方完成它的資料發送任務後就能發送一個FIN來終止這個方向的串連。收到一個
FIN只意味著這一方向上沒有資料流動,一個TCP串連在收到一個FIN後仍能發送資料。首先進行關閉的一方將執行主動關閉,而另一方執行被動關閉。
 (1) TCP用戶端發送一個FIN,用來關閉客戶到伺服器的資料傳送(報文段4)。
 (2) 伺服器收到這個FIN,它發回一個ACK,確認序號為收到的序號加1(報文段5)。和SYN一樣,一個FIN將佔用一個序號。
 (3) 伺服器關閉用戶端的串連,發送一個FIN給用戶端(報文段6)。
 (4) 客戶段發回ACK報文確認,並將確認序號設定為收到序號加1(報文段7)。

CLOSED: 這個沒什麼好說的了,表示初始狀態。

LISTEN: 這個也是非常容易理解的一個狀態,表示伺服器端的某個SOCKET處於監聽狀態,可以接受串連了。

SYN_RCVD:

這個狀態表示接受到了SYN報文,在正常情況下,這個狀態是伺服器端的SOCKET在建立TCP串連時的三向交握會話過程中的一個中間狀態,很短暫,基本
上用netstat你是很難看到這種狀態的,除非你特意寫了一個用戶端測試程式,故意將三次TCP握手過程中最後一個ACK報文不予發送。因此這種狀態
時,當收到用戶端的ACK報文後,它會進入到ESTABLISHED狀態。

SYN_SENT:

這個狀態與SYN_RCVD遙想呼應,當用戶端SOCKET執行CONNECT串連時,它首先發送SYN報文,因此也隨即它會進入到了SYN_SENT狀
態,並等待服務端的發送三向交握中的第2個報文。SYN_SENT狀態表示用戶端已發送SYN報文。

ESTABLISHED:這個容易理解了,表示串連已經建立了。

FIN_WAIT_1:

這個狀態要好好解釋一下,其實FIN_WAIT_1和FIN_WAIT_2狀態的真正含義都是表示等待對方的FIN報文。而這兩種狀態的區別
是:FIN_WAIT_1狀態實際上是當SOCKET在ESTABLISHED狀態時,它想主動關閉串連,向對方發送了FIN報文,此時該SOCKET即
進入到FIN_WAIT_1狀態。而當對方回應ACK報文後,則進入到FIN_WAIT_2狀態,當然在實際的正常情況下,無論對方何種情況下,都應該馬
上回應ACK報文,所以FIN_WAIT_1狀態一般是比較難見到的,而FIN_WAIT_2狀態還有時常常可以用netstat看到。

FIN_WAIT_2:上面已經詳細解釋了這種狀態,實際上FIN_WAIT_2狀態下的SOCKET,表示半串連,也即有一方要求close串連,但另外還告訴對方,我暫時還有點資料需要傳送給你,稍後再關閉串連。

TIME_WAIT:

表示收到了對方的FIN報文,並發送出了ACK報文,就等2MSL後即可回到CLOSED可用狀態了。如果FIN_WAIT_1狀態下,收到了對方同時帶
FIN標誌和ACK標誌的報文時,可以直接進入到TIME_WAIT狀態,而無須經過FIN_WAIT_2狀態。

CLOSING:

這種狀態比較特殊,實際情況中應該是很少見,屬於一種比較罕見的例外狀態。正常情況下,當你發送FIN報文後,按理來說是應該先收到(或同時收到)對方的
ACK報文,再收到對方的FIN報文。但是CLOSING狀態表示你發送FIN報文後,並沒有收到對方的ACK報文,反而卻也收到了對方的FIN報文。什
麼情況下會出現此種情況呢?其實細想一下,也不難得出結論:那就是如果雙方几乎在同時close一個SOCKET的話,那麼就出現了雙方同時發送FIN報
文的情況,也即會出現CLOSING狀態,表示雙方都正在關閉SOCKET串連。

CLOSE_WAIT:

這種狀態的含義其實是表示在等待關閉。怎麼理解呢?當對方close一個SOCKET後發送FIN報文給自己,你系統毫無疑問地會回應一個ACK報文給對
方,此時則進入到CLOSE_WAIT狀態。接下來呢,實際上你真正需要考慮的事情是察看你是否還有資料發送給對方,如果沒有的話,那麼你也就可以
close這個SOCKET,發送FIN報文給對方,也即關閉串連。所以你在CLOSE_WAIT狀態下,需要完成的事情是等待你去關閉串連。

LAST_ACK: 這個狀態還是比較容易好理解的,它是被動關閉一方在發送FIN報文後,最後等待對方的ACK報文。當收到ACK報文後,也即可以進入到CLOSED可用狀態了。

最後有2個問題的回答,我自己分析後的結論(不一定保證100%正確):

1、 為什麼建立連線協定是三向交握,而關閉串連卻是四次握手呢?

是因為服務端的LISTEN狀態下的SOCKET當收到SYN報文的建連請求後,它可以把ACK和SYN(ACK起應答作用,而SYN起同步作用)放在一
個報文裡來發送。但關閉串連時,當收到對方的FIN報文通知時,它僅僅表示對方沒有資料發送給你了;但未必你所有的資料都全部發送給對方了,所以你可以未
必會馬上會關閉SOCKET,也即你可能還需要發送一些資料給對方之後,再發送FIN報文給對方來表示你同意現在可以關閉串連了,所以它這裡的ACK報文
和FIN報文多數情況下都是分開發送的。

2、 為什麼TIME_WAIT狀態還需要等2MSL後才能返回到CLOSED狀態?

是因為:雖然雙方都同意關閉串連了,而且握手的4個報文也都協調和發送完畢,按理可以直接回到CLOSED狀態(就好比從SYN_SEND狀態到
ESTABLISH狀態那樣);但是因為我們必須要假想網路是不可靠的,你無法保證你最後發送的ACK報文會一定被對方收到,因此對方處於
LAST_ACK狀態下的SOCKET可能會因為逾時未收到ACK報文,而重發FIN報文,所以這個TIME_WAIT狀態的作用就是用來重發可能丟失的
ACK報文。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.