天天看點

TCP的三次握手(建立連接配接)和四次揮手(關閉連接配接)wireshark抓包圖解 TCP三向交握/四次揮手詳解 TCP的TIME_WAIT和Close_Wait狀态

TCP的三次握手(建立連接配接)和四次揮手(關閉連接配接)

參照:

http://course.ccniit.com/CSTD/Linux/reference/files/018.PDF

http://hi.baidu.com/raycomer/item/944d23d9b502d13be3108f61

 http://blog.csdn.net/risingsun001/article/details/44453685?ref=myread

wireshark抓包圖解 TCP三向交握/四次揮手詳解

建立連接配接: 

了解:視窗和滑動視窗
TCP的流量控制
      

TCP使用視窗機制進行流量控制 什麼是視窗?

連接配接建立時,各端配置設定一塊緩沖區用來存儲接收的資料,并将緩沖區的尺寸發送給另一端

接收方發送的确認資訊中包含了自己剩餘的緩沖區尺寸

剩餘緩沖區空間的數量叫做視窗

2. TCP的流控過程(滑動視窗)

TCP的三次握手(建立連接配接)和四次揮手(關閉連接配接)wireshark抓包圖解 TCP三向交握/四次揮手詳解 TCP的TIME_WAIT和Close_Wait狀态

TCP(Transmission Control Protocol) 傳輸控制協定

三次握手

TCP是主機對主機層的傳輸控制協定,提供可靠的連接配接服務,采用三次握手确認建立一個連接配接:

位碼即tcp标志位,有6種标示:

SYN(synchronous建立聯機)

ACK(acknowledgement 确認)

PSH(push傳送)

FIN(finish結束)

RST(reset重置)

URG(urgent緊急)

Sequence number(順序号碼)

Acknowledge number(确認号碼)

序号:32bit的序列号,由發送方使用

用戶端TCP狀态遷移:

CLOSED->SYN_SENT->ESTABLISHED->FIN_WAIT_1->FIN_WAIT_2->TIME_WAIT->CLOSED

伺服器TCP狀态遷移:

CLOSED->LISTEN->SYN收到->ESTABLISHED->CLOSE_WAIT->LAST_ACK->CLOSED

TCP的三次握手(建立連接配接)和四次揮手(關閉連接配接)wireshark抓包圖解 TCP三向交握/四次揮手詳解 TCP的TIME_WAIT和Close_Wait狀态

各個狀态的意義如下: 

LISTEN - 偵聽來自遠方TCP端口的連接配接請求; 

SYN-SENT -在發送連接配接請求後等待比對的連接配接請求; 

SYN-RECEIVED - 在收到和發送一個連接配接請求後等待對連接配接請求的确認; 

ESTABLISHED- 代表一個打開的連接配接,資料可以傳送給使用者; 

FIN-WAIT-1 - 等待遠端TCP的連接配接中斷請求,或先前的連接配接中斷請求的确認;

FIN-WAIT-2 - 從遠端TCP等待連接配接中斷請求; 

CLOSE-WAIT - 等待從本地使用者發來的連接配接中斷請求; 

CLOSING -等待遠端TCP對連接配接中斷的确認; 

LAST-ACK - 等待原來發向遠端TCP的連接配接中斷請求的确認; 

TIME-WAIT -等待足夠的時間以確定遠端TCP接收到連接配接中斷請求的确認; 

CLOSED - 沒有任何連接配接狀态;

TCP/IP協定中,TCP協定提供可靠的連接配接服務,采用三次握手建立一個連接配接,如圖1所示。

(1)第一次握手:建立連接配接時,用戶端A發送SYN包(SYN=j)到伺服器B,并進入SYN_SEND狀态,等待伺服器B确認。

(2)第二次握手:伺服器B收到SYN包,必須确認客戶A的SYN(ACK=j+1),同時自己也發送一個SYN包(SYN=k),即SYN+ACK包,此時伺服器B進入SYN_RECV狀态。

(3)第三次握手:用戶端A收到伺服器B的SYN+ACK包,向伺服器B發送确認包ACK(ACK=k+1),此包發送完畢,用戶端A和伺服器B進入ESTABLISHED狀态,完成三次握手。

完成三次握手,用戶端與伺服器開始傳送資料。

确認号:其數值等于發送方的發送序号 +1(即接收方期望接收的下一個序列号)。

 比如下面:第一次握手:主機A是發送方,它發送的序列号是200,主機B是接收方,收到之後發送确認号201,就是說B要A發送序列号201的資料。

是以第二次握手的時候ACK=201

第二次握手:主機B是發送方,它發送的序列号是500,主機A是接收方,收到之後發送确認号501,就是說A要B發送序列号501的資料。

是以第三次握手的時候ACK=501,主機A的發送序号是201,滿足B第二次握手的請求。

TCP的三次握手(建立連接配接)和四次揮手(關閉連接配接)wireshark抓包圖解 TCP三向交握/四次揮手詳解 TCP的TIME_WAIT和Close_Wait狀态

圖1 TCP三向交握建立連接配接  

TCP的三次握手(建立連接配接)和四次揮手(關閉連接配接)wireshark抓包圖解 TCP三向交握/四次揮手詳解 TCP的TIME_WAIT和Close_Wait狀态

TCP的標頭結構:

源端口 16位

目标端口 16位

序列号 32位

回應序号 32位

TCP頭長度 4位

reserved 6位

控制代碼 6位

視窗大小 16位

偏移量 16位

校驗和 16位

選項  32位(可選)

這樣我們得出了TCP標頭的最小長度,為20位元組

TCP三向交握   所謂三次握手(Three-way Handshake),是指建立一個TCP連接配接時,需要用戶端和伺服器總共發送3個包。   三次握手的目的是連接配接伺服器指定端口,建立TCP連接配接,并同步連接配接雙方的序列号和确認号并交換 TCP 視窗大小資訊.在socket 程式設計中,用戶端執行connect()時。将觸發三次握手。  

TCP的三次握手(建立連接配接)和四次揮手(關閉連接配接)wireshark抓包圖解 TCP三向交握/四次揮手詳解 TCP的TIME_WAIT和Close_Wait狀态

第一次握手: 用戶端發送一個TCP的SYN标志位置1的包指明客戶打算連接配接的伺服器的端口,以及初始序号X,儲存在標頭的序列号(Sequence Number)字段裡。  www.2cto.com  

TCP的三次握手(建立連接配接)和四次揮手(關閉連接配接)wireshark抓包圖解 TCP三向交握/四次揮手詳解 TCP的TIME_WAIT和Close_Wait狀态

  第二次握手: 伺服器發回确認包(ACK)應答。即SYN标志位和ACK标志位均為1同時,将确認序号(Acknowledgement Number)設定為客戶的I S N加1以.即X+1。  

TCP的三次握手(建立連接配接)和四次揮手(關閉連接配接)wireshark抓包圖解 TCP三向交握/四次揮手詳解 TCP的TIME_WAIT和Close_Wait狀态

  第三次握手. 用戶端再次發送确認包(ACK) SYN标志位為0,ACK标志位為1.并且把伺服器發來ACK的序号字段+1,放在确定字段中發送給對方.并且在資料段放寫ISN的+1

TCP的三次握手(建立連接配接)和四次揮手(關閉連接配接)wireshark抓包圖解 TCP三向交握/四次揮手詳解 TCP的TIME_WAIT和Close_Wait狀态

  SYN攻擊    在三次握手過程中,伺服器發送SYN-ACK之後,收到用戶端的ACK之前的TCP連接配接稱為半連接配接(half-open connect).此時伺服器處于Syn_RECV狀态.當收到ACK後,伺服器轉入ESTABLISHED狀态.   Syn攻擊就是 攻擊用戶端 在短時間内僞造大量不存在的IP位址,向伺服器不斷地發送syn包,伺服器回複确認包,并等待客戶的确認,由于源位址是不存在的,伺服器需要不斷的重發直 至逾時,這些僞造的SYN包将長時間占用未連接配接隊列,正常的SYN請求被丢棄,目标 系統運作緩慢,嚴重者引起網絡堵塞甚至系統癱瘓。  Syn攻擊是一個典型的DDOS攻擊。檢測SYN攻擊非常的友善,當你在伺服器上看到大量的半連接配接狀态時,特别是源IP位址是随機的,基本上可以斷定這是一次SYN攻擊.在 Linux下可以如下指令檢測是否被Syn攻擊 netstat -n -p TCP | grep SYN_RECV

  一般較新的TCP/IP協定棧都對這一過程進行修正來防範Syn攻擊,修改tcp協定實作。主要方法有SynAttackProtect保護機制、SYN cookies技術、增加最大半連接配接和縮短逾時時間等. 但是不能完全防範syn攻擊。  www.2cto.com   TCP 四次揮手 TCP的連接配接的拆除需要發送四個包,是以稱為四次揮手(four-way handshake)。用戶端或伺服器均可主動發起揮手動作,在socket程式設計中,任何一方執行close()操作即可産生揮手操作。  

TCP的三次握手(建立連接配接)和四次揮手(關閉連接配接)wireshark抓包圖解 TCP三向交握/四次揮手詳解 TCP的TIME_WAIT和Close_Wait狀态

  參見wireshark抓包,實測的抓包結果并沒有嚴格按揮手時序。我估計是時間間隔太短造成。  

TCP的三次握手(建立連接配接)和四次揮手(關閉連接配接)wireshark抓包圖解 TCP三向交握/四次揮手詳解 TCP的TIME_WAIT和Close_Wait狀态

  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将占用一個序号。  www.2cto.com    (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狀态下,需要完成的事情是等待你去關閉連接配接。  www.2cto.com   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封包。

下面是具體的例子截圖: 1.此圖包含兩部分資訊:TCP的三次握手(方框中的内容) (SYN, (SYN+ACK), ACK) 2. TCP的資料傳輸 ([TCP segment of a reassembled PUD])可以看出,server是将資料TCP層對消息包進行分片傳輸 (1)Server端收到HTTP請求如GET之後,構造響應消息,其中攜帶網頁内容,在server端的HTTP層發送消息200 OK->server端的TCP層; 

(2)server端的TCP層對消息包進行分片傳輸; 

(3)client端的TCP層對接收到的各個消息包分片回送響應; 

(4)client端的TCP層每次收到一部分都會用ACK确認,之後server繼續傳輸,client繼續确認,直到完成響應消息的所有分片之後,Server 發送組合HTTP響應包 200 OK,此時在client端的消息跟蹤中才可以顯示 HTTP 200 OK的消息包

TCP的三次握手(建立連接配接)和四次揮手(關閉連接配接)wireshark抓包圖解 TCP三向交握/四次揮手詳解 TCP的TIME_WAIT和Close_Wait狀态

關閉連接配接:

由于TCP連接配接是全雙工的,是以每個方向都必須單獨進行關閉。這個原則是當一方完成它的資料發送任務後就能發送一個FIN來終止這個方向的連接配接。收到一個 FIN隻意味着這一方向上沒有資料流動,一個TCP連接配接在收到一個FIN後仍能發送資料。首先進行關閉的一方将執行主動關閉,而另一方執行被動關閉。

 CP的連接配接的拆除需要發送四個包,是以稱為四次揮手(four-way handshake)。用戶端或伺服器均可主動發起揮手動作,在socket程式設計中,任何一方執行close()操作即可産生揮手操作。

(1)用戶端A發送一個FIN,用來關閉客戶A到伺服器B的資料傳送。 

(2)伺服器B收到這個FIN,它發回一個ACK,确認序号為收到的序号加1。和SYN一樣,一個FIN将占用一個序号。 

(3)伺服器B關閉與用戶端A的連接配接,發送一個FIN給用戶端A。 

(4)用戶端A發回ACK封包确認,并将确認序号設定為收到序号加1。 

TCP采用四次揮手關閉連接配接如圖2所示。

TCP的三次握手(建立連接配接)和四次揮手(關閉連接配接)wireshark抓包圖解 TCP三向交握/四次揮手詳解 TCP的TIME_WAIT和Close_Wait狀态

 圖2  TCP四次揮手關閉連接配接

參見wireshark抓包,實測的抓包結果并沒有嚴格按揮手時序。我估計是時間間隔太短造成。

TCP的三次握手(建立連接配接)和四次揮手(關閉連接配接)wireshark抓包圖解 TCP三向交握/四次揮手詳解 TCP的TIME_WAIT和Close_Wait狀态

深入了解TCP連接配接的釋放: 

由于TCP連接配接是全雙工的,是以每個方向都必須單獨進行關閉。這原則是當一方完成它的資料發送任務後就能發送一個FIN來終止這個方向的連接配接。收到一個 FIN隻意味着這一方向上沒有資料流動,一個TCP連接配接在收到一個FIN後仍能發送資料。首先進行關閉的一方将執行主動關閉,而另一方執行被動關閉。

TCP協定的連接配接是全雙工連接配接,一個TCP連接配接存在雙向的讀寫通道。 

簡單說來是 “先關讀,後關寫”,一共需要四個階段。以客戶機發起關閉連接配接為例:

1.伺服器讀通道關閉

2.客戶機寫通道關閉

3.客戶機讀通道關閉

4.伺服器寫通道關閉

關閉行為是在發起方資料發送完畢之後,給對方發出一個FIN(finish)資料段。直到接收到對方發送的FIN,且對方收到了接收确認ACK之後,雙方的資料通信完全結束,過程中每次接收都需要傳回确認資料段ACK。

詳細過程:

    第一階段   客戶機發送完資料之後,向伺服器發送一個FIN資料段,序列号為i;

    1.伺服器收到FIN(i)後,傳回确認段ACK,序列号為i+1,關閉伺服器讀通道;

    2.客戶機收到ACK(i+1)後,關閉客戶機寫通道;

   (此時,客戶機仍能通過讀通道讀取伺服器的資料,伺服器仍能通過寫通道寫資料)

    第二階段 伺服器發送完資料之後,向客戶機發送一個FIN資料段,序列号為j;

    3.客戶機收到FIN(j)後,傳回确認段ACK,序列号為j+1,關閉客戶機讀通道;

    4.伺服器收到ACK(j+1)後,關閉伺服器寫通道。

這是标準的TCP關閉兩個階段,伺服器和客戶機都可以發起關閉,完全對稱。

FIN辨別是通過發送最後一塊資料時設定的,标準的例子中,伺服器還在發送資料,是以要等到發送完的時候,設定FIN(此時可稱為TCP連接配接處于半關閉狀态,因為資料仍可從被動關閉一方向主動關閉方傳送)。如果在伺服器收到FIN(i)時,已經沒有資料需要發送,可以在傳回ACK(i+1)的時候就設定FIN(j)辨別,這樣就相當于可以合并第二步和第三步。讀《Linux網絡程式設計》關閉TCP連接配接章節,作以下筆記:

TCP的TIME_WAIT和Close_Wait狀态

面試時看到應聘者履歷中寫精通網絡,TCP程式設計,我常問一個問題,TCP建立連接配接需要幾次握手?95%以上的應聘者都能答對是3次。問TCP斷開連接配接需要幾次握手,70%的應聘者能答對是4次通訊。再問CLOSE_WAIT,TIME_WAIT是什麼狀态,怎麼産生的,對服務有什麼影響,如何消除?有一部分同學就回答不上來。不是我扣細節,而是在通訊為主的前端伺服器上,必須有能力處理各種TCP狀态。比如統計在本廠的一台前端機上高峰時間TCP連接配接的情況,統計指令:

  1. netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'  

結果:

TCP的三次握手(建立連接配接)和四次揮手(關閉連接配接)wireshark抓包圖解 TCP三向交握/四次揮手詳解 TCP的TIME_WAIT和Close_Wait狀态

除了ESTABLISHED,可以看到連接配接數比較多的幾個狀态是:FIN_WAIT1, TIME_WAIT, CLOSE_WAIT, SYN_RECV和LAST_ACK;下面的文章就這幾個狀态的産生條件、對系統的影響以及處理方式進行簡單描述。

TCP狀态

TCP狀态如下圖所示:

TCP的三次握手(建立連接配接)和四次揮手(關閉連接配接)wireshark抓包圖解 TCP三向交握/四次揮手詳解 TCP的TIME_WAIT和Close_Wait狀态

可能有點眼花缭亂?再看看這個時序圖

TCP的三次握手(建立連接配接)和四次揮手(關閉連接配接)wireshark抓包圖解 TCP三向交握/四次揮手詳解 TCP的TIME_WAIT和Close_Wait狀态

下面看下大家一般比較關心的三種TCP狀态

SYN_RECV 

服務端收到建立連接配接的SYN沒有收到ACK包的時候處在SYN_RECV狀态。有兩個相關系統配置:

1,net.ipv4.tcp_synack_retries :INTEGER

預設值是5

對于遠端的連接配接請求SYN,核心會發送SYN + ACK資料報,以确認收到上一個 SYN連接配接請求包。這是所謂的三次握手( threeway handshake)機制的第二個步驟。這裡決定核心在放棄連接配接之前所送出的 SYN+ACK 數目。不應該大于255,預設值是5,對應于180秒左右時間。通常我們不對這個值進行修改,因為我們希望TCP連接配接不要因為偶爾的丢包而無法建立。

2,net.ipv4.tcp_syncookies

一般伺服器都會設定net.ipv4.tcp_syncookies=1來防止SYN Flood攻擊。假設一個使用者向伺服器發送了SYN封包後突然當機或掉線,那麼伺服器在發出SYN+ACK應答封包後是無法收到用戶端的ACK封包的(第三次握手無法完成),這種情況下伺服器端一般會重試(再次發送SYN+ACK給用戶端)并等待一段時間後丢棄這個未完成的連接配接,這段時間的長度我們稱為SYN Timeout,一般來說這個時間是分鐘的數量級(大約為30秒-2分鐘)。

這些處在SYNC_RECV的TCP連接配接稱為半連接配接,并存儲在核心的半連接配接隊列中,在核心收到對端發送的ack包時會查找半連接配接隊列,并将符合的requst_sock資訊存儲到完成三次握手的連接配接的隊列中,然後删除此半連接配接。大量SYNC_RECV的TCP連接配接會導緻半連接配接隊列溢出,這樣後續的連接配接建立請求會被核心直接丢棄,這就是SYN Flood攻擊。

能夠有效防範SYN Flood攻擊的手段之一,就是SYN Cookie。SYN Cookie原理由D. J. Bernstain和 Eric Schenk發明。SYN Cookie是對TCP伺服器端的三次握手協定作一些修改,專門用來防範SYN Flood攻擊的一種手段。它的原理是,在TCP伺服器收到TCP SYN包并傳回TCP SYN+ACK包時,不配置設定一個專門的資料區,而是根據這個SYN包計算出一個cookie值。在收到TCP ACK包時,TCP伺服器在根據那個cookie值檢查這個TCP ACK包的合法性。如果合法,再配置設定專門的資料區進行處理未來的TCP連接配接。

觀測服務上SYN_RECV連接配接個數為:7314,對于一個高并發連接配接的通訊伺服器,這個數字比較正常。

CLOSE_WAIT

發起TCP連接配接關閉的一方稱為client,被動關閉的一方稱為server。被動關閉的server收到FIN後,但未發出ACK的TCP狀态是CLOSE_WAIT。出現這種狀況一般都是由于server端代碼的問題,如果你的伺服器上出現大量CLOSE_WAIT,應該要考慮檢查代碼。

TIME_WAIT

根據TCP協定定義的3次握手斷開連接配接規定,發起socket主動關閉的一方 socket将進入TIME_WAIT狀态。TIME_WAIT狀态将持續2個MSL(Max Segment Lifetime),在Windows下預設為4分鐘,即240秒。TIME_WAIT狀态下的socket不能被回收使用. 具展現象是對于一個處理大量短連接配接的伺服器,如果是由伺服器主動關閉用戶端的連接配接,将導緻伺服器端存在大量的處于TIME_WAIT狀态的socket, 甚至比處于Established狀态下的socket多的多,嚴重影響伺服器的處理能力,甚至耗盡可用的socket,停止服務。

為什麼需要TIME_WAIT?TIME_WAIT是TCP協定用以保證被重新配置設定的socket不會受到之前殘留的延遲重發封包影響的機制,是必要的邏輯保證。

和TIME_WAIT狀态有關的系統參數有一般由3個,本廠設定如下:

net.ipv4.tcp_tw_recycle = 1

net.ipv4.tcp_tw_reuse = 1

net.ipv4.tcp_fin_timeout = 30

net.ipv4.tcp_fin_timeout,預設60s,減小fin_timeout,減少TIME_WAIT連接配接數量。

net.ipv4.tcp_tw_reuse = 1表示開啟重用。允許将TIME-WAIT sockets重新用于新的TCP連接配接,預設為0,表示關閉;

net.ipv4.tcp_tw_recycle = 1表示開啟TCP連接配接中TIME-WAIT sockets的快速回收,預設為0,表示關閉。

為了友善描述,我給這個TCP連接配接的一端起名為Client,給另外一端起名為Server。上圖描述的是Client主動關閉的過程,FTP協定中就這樣的。如果要描述Server主動關閉的過程,隻要交換描述過程中的Server和Client就可以了,HTTP協定就是這樣的。

描述過程:

Client調用close()函數,給Server發送FIN,請求關閉連接配接;Server收到FIN之後給Client傳回确認ACK,同時關閉讀通道(不清楚就去看一下shutdown和close的差别),也就是說現在不能再從這個連接配接上讀取東西,現在read傳回0。此時Server的TCP狀态轉化為CLOSE_WAIT狀态。

Client收到對自己的FIN确認後,關閉 寫通道,不再向連接配接中寫入任何資料。

接下來Server調用close()來關閉連接配接,給Client發送FIN,Client收到後給Server回複ACK确認,同時Client關閉讀通道,進入TIME_WAIT狀态。

Server接收到Client對自己的FIN的确認ACK,關閉寫通道,TCP連接配接轉化為CLOSED,也就是關閉連接配接。

Client在TIME_WAIT狀态下要等待最大資料段生存期的兩倍,然後才進入CLOSED狀态,TCP協定關閉連接配接過程徹底結束。

以上就是TCP協定關閉連接配接的過程,現在說一下TIME_WAIT狀态。

從上面可以看到,主動發起關閉連接配接的操作的一方将達到TIME_WAIT狀态,而且這個狀态要保持Maximum Segment Lifetime的兩倍時間。為什麼要這樣做而不是直接進入CLOSED狀态?

原因有二:

一、保證TCP協定的全雙工連接配接能夠可靠關閉

二、保證這次連接配接的重複資料段從網絡中消失

先說第一點,如果Client直接CLOSED了,那麼由于IP協定的不可靠性或者是其它網絡原因,導緻Server沒有收到Client最後回複的ACK。那麼Server就會在逾時之後繼續發送FIN,此時由于Client已經CLOSED了,就找不到與重發的FIN對應的連接配接,最後Server就會收到RST而不是ACK,Server就會以為是連接配接錯誤把問題報告給高層。這樣的情況雖然不會造成資料丢失,但是卻導緻TCP協定不符合可靠連接配接的要求。是以,Client不是直接進入CLOSED,而是要保持TIME_WAIT,當再次收到FIN的時候,能夠保證對方收到ACK,最後正确的關閉連接配接。

再說第二點,如果Client直接CLOSED,然後又再向Server發起一個新連接配接,我們不能保證這個新連接配接與剛關閉的連接配接的端口号是不同的。也就是說有可能新連接配接和老連接配接的端口号是相同的。一般來說不會發生什麼問題,但是還是有特殊情況出現:假設新連接配接和已經關閉的老連接配接端口号是一樣的,如果前一次連接配接的某些資料仍然滞留在網絡中,這些延遲資料在建立新連接配接之後才到達Server,由于新連接配接和老連接配接的端口号是一樣的,又因為TCP協定判斷不同連接配接的依據是socket pair,于是,TCP協定就認為那個延遲的資料是屬于新連接配接的,這樣就和真正的新連接配接的資料包發生混淆了。是以TCP連接配接還要在TIME_WAIT狀态等待2倍MSL,這樣可以保證本次連接配接的所有資料都從網絡中消失。

各種協定都是前人千錘百煉後得到的标準,規範。從細節中都能感受到精巧和嚴謹。每次深入都有同一個感覺,精妙。

做個快樂的自己。

繼續閱讀