一、引言
TCP是一個面向連接的協議。無論哪一方向另一方發送數據之前,都必須先在雙方之間建立一條連接。連接創建與終止的狀態變化圖如下:
二、三次握手建立連接
過程如下:
- 客戶端發送一個SYN數據包指明客戶端打算連接服務器的端口,初始化序號(ISN)為m。
- 服務器發回包含服務器的ISN作為應答(值為n)。同時,將確認序號設置成客戶端ISN+1(m+1)來作為對客戶端SYN的確認。
- 客戶端發送一個ACK數據包,ack=n+1,作為對服務器的SYN的確認。
1.為什么是三次握手,而不是兩次
網絡是不可靠的,數據包是可能丟失的
。假設沒有第三次確認,客戶端向服務端發送了 SYN,請求建立連接。由于延遲,服務端沒有及時收到這個包。于是客戶端重新發送一個 SYN 包。回憶一下介紹 TCP 首部時提到的序列號,這兩個包的序列號顯然是相同的。假設服務端接收到了第二個 SYN 包,建立了通信,一段時間后通信結束,連接被關閉。這時候最初被發送的 SYN 包剛剛抵達服務端,服務端又會發送一次 ACK 確認。由于兩次握手就建立了連接,此時的服務端就會建立一個新的連接,然而客戶端覺得自己并沒有請求建立連接,所以就不會向服務端發送數據。從而導致服務端建立了一個空的連接,白白浪費資源。
??TCP是雙通道,需要雙向確定
。只有兩次握手,客戶端知道了服務器收到了,服務器不知道客戶端收到了,聯想打電話。通訊系統中的占拜庭將軍問題。
2.最大報文段長度
最大報文段長度(MSS)表示TCP傳往另一端的最大塊數據的長度。當一個連接建立時,連接的雙方都要通告各自的MSS。在三次握手的時候SYN的TCP首部中的可選字段確定。以太網的默認長度為1460。
3.
三、四次握手關閉連接(正常狀態)
建立一個連接需要三次握手,而終止一個連接要經過4次握手。這由TCP的半關閉(half-close)造成的。一個TCP連接是全雙工(即數據在兩個方向上能同時傳遞),因此每個方向必須單獨地進行關閉。
- 主動方想要關閉連接,發送FIN包給被動方,序號為m
- 被動方接收到主動方發送的FIN包,知道了對方要關閉連接,發送ACK確認包,序號m+1。主動方連接關閉。
- 等待片刻(處于半關閉狀態),在此期間(fin_wait2,close_wait)。被動方發送最后的數據,主動方接收最后的數據。
- 被動方確認要關閉連接,發送FIN包。序號n。
- 主動方等待片刻(接收網絡中,還未到達的數據包),發送ACK確認包。序號n+1。到此連接關閉。
1.TCP的半關閉狀態
TCP提供了連接的一端在結束它的發送后還能接收來自另一端數據的能力。如主動方處于fin_wait2狀態。
2.TIME_WAIT狀態
TIME_WAIT狀態也稱為2MSL等待狀態。每個具體TCP實現必須選擇一個報文段最大生存時間MSL( Maximum Segment Lifetime)。它是任何報文段被丟棄前在網絡內的最長時間。因為TCP報文段以IP數據報在網絡內傳輸,而IP數據報則有限制其生存時間的TTL字段。在實際應用中,對 I P數據報TTL的限制是基于跳數,而不是定時器。
??在處于2MSL等待狀態的socket(客戶端IP與端口,服務器IP與端口)不能再被使用。但在實際的使用中,允許一個新的連接請求到達仍處于time_wait狀態的連接,只要新的序號大于該連接的前一個連接的最后序號。
四、正常狀態抓包
下面是一次完整的tcp建立連接,發送數據,關閉連接過程
該過程為,3次握手建立連接,一次數據發送,4次握手關閉連接
五、異常情況
出現異常的時候,服務器通常通過復位報文來通告,復位報文為tcp數據包類型設置為rst。
1.連接超時或到達不存在的端口/服務器
當服務器端沒有開或網絡問題,會出現連接超時的情況。抓包如下:
客戶端嘗試3三次來連接,有時候服務器端會發送rst數據包。
2.異常終止一個連接
在TCP通訊中。如果通訊雙方應為某種原因(如突然斷電等)關閉連接時候一方(如A)沒有發送fin數據包。另一端(如B)不知道對方已經關閉了連接。再次發送數據的時候,異常關閉的一方,可能會返回一個rst數據包。通知異常關閉。如果一方已經關閉或異常終止連接而另一方卻還不知道,我們將這樣的TCP連接稱為半打開(Half Open)的。
3.同時打開
兩個應用程序同時彼此執行主動打開的情況是可能的。每一方必須發送一個SYN,且這些SYN必須傳遞給對方。這需要每一方使用一個對方熟知的端口作為本地端口。同時打開的狀態遷移圖不同于正常狀態的三次握手,該情況下需要進行4次握手。如圖:
4.同時關閉
我們在以前討論過一方(通常但不總是客戶方)發送第一個FIN執行主動關閉。雙方都執行主動關閉也是可能的,TCP協議也允許這樣的同時關閉(simultaneous close)。在同時關閉的時候,雙方都進入time_wait狀態,如圖:
六.TCP服務器設計
大多數的TCP服務器進程是并發的。當一個新的連接請求到達服務器時,服務器接受這個請求,并調用一個新進程來處理這個新的客戶請求。
1. 接入連接請求隊列
一個并發服務器調用一個新的進程來處理每個客戶請求,因此處于被動連接請求的服務器應該始終準備處理下一個呼入的連接請求。那正是使用并發服務器的根本原因。但仍有可能出現當服務器在創建一個新的進程時,或操作系統正忙于處理優先級更高的進程時,到達多個連接請求。當服務器正處于忙時,TCP是如何處理這些呼入的連接請求?TCP有這樣一個隊列來臨時存放這些連接-接入連接請求隊列。處理方式如下:
- 正等待連接請求的一端有一個固定長度的連接隊列,該隊列中的連接已被TCP接受(即三次握手已經完成),但還沒有被應用層所接受。注意區分TCP接受一個連接是將其放入這個隊列,而應用層接受連接是將其從該隊列中移出。
- 應用層將指明該隊列的最大長度,這個值通常稱為積壓值 (backlog)。
- 當一個連接請求(SYN)到達時, TCP使用一個算法,根據當前連接隊列中的連接數來確定是否接收這個連接。積壓值說明的是TCP監聽的端口已被TCP接受而等待應用層接受的最大連接數。
- 如果對于新的連接請求,該TCP監聽的端口的連接隊列中還有空間,TCP模塊將對SYN進行確認并完成連接的建立。此時,應用層不一定知道該新的連接,如果對方發送數據,這些數據將放入緩沖隊列中。
- 如果對于新的連接請求,連接隊列中已沒有空間,TCP將不理會收到的SYN。也不發回任何報文段(即不發回 RST)。如果應用層不能及時接受已被TCP接受的連接,這些連接可能占滿整個連接隊列,客戶的主動打開最終將超時。
都看到這里了,要不要掃二維碼關注一下微信公眾號林灣村龍貓。