1. 程式人生 > 實用技巧 >關於TCP的三次握手和四次揮手的分析

關於TCP的三次握手和四次揮手的分析

  • 在網路分析中,讀懂TCP序列號和確認號的值,可以幫助我們學習TCP協議以及排查問題,如通過檢視序列號和確認號可以確定資料傳輸是否亂序。
  • TCP通訊中主要有連線的建立、資料的傳輸、連線的關閉三個過程。每個過程完成不同的工作,而且序列號和確認號在每個過程中的變化都是不同的。
  • TCP協議工作在傳輸層,是一種可靠的面向連線的資料流協議。TCP之所以可靠,是因為它保證了傳送資料包的順序。順序是用一個序列號來保證的。

TCP報文格式詳解:

https://blog.csdn.net/mary19920410/article/details/58030147

對於seq和ack的理解:

seq是序列號,這是為了連線以後傳送資料用的(當然連結的時候也用),

ack是對收到的資料包的確認,值是等待接收的資料包的序列號。

第一次訊息傳送中,A隨機選取一個序列號x作為自己的初始序號傳送給B;

第二次訊息B使用ack對A的資料包進行確認,因為已經收到了序列號為x的資料包,準備接收序列號為x+1的包,所以ack=x+1,同時B告訴A自己的初始序列號,就是seq=y;

第三條訊息A告訴B收到了B的確認訊息並準備建立連線,A自己此條訊息的序列號是x+1,所以seq=x+1(即按照規矩就是上面ack的值),而ack=y+1是表示A正準備接收B序列號為y+1的資料包。

seq是資料包本身的序列號;

ack是期望對方下一個傳送的資料包的序列號。

對於FLAGS欄位表示的理解:

在TCP層,有個FLAGS欄位,這個欄位有以下幾個標識:SYN, FIN, ACK, PSH, RST, URG.(6個)

SYN(synchronous建立聯機) 表示建立連線

ACK(acknowledgement 確認) 表示響應

PSH(push傳送) 表示有 DATA資料傳輸

FIN(finish結束) 表示關閉連線

RST(reset重置) 表示連線重置。

URG(urgent緊急)

  • 其中,ACK是可能與SYN,FIN等同時使用的,比如SYN和ACK可能同時為1,它表示的就是建立連線之後的響應,
  • 如果只是單個的一個SYN,它表示的只是建立連線。
  • 當出現SYN和SYN+ACK包時,我們認為客戶端與伺服器建立了一個連線。TCP的幾次握手就是通過這樣的ACK表現出來的。
  • 但SYN與FIN是不會同時為1的,因為前者表示的是建立連線,而後者表示的是斷開連線。
  • RST一般是在FIN之後才會出現為1的情況,表示的是連線重置。
  • 一般地,當出現FIN包或RST包時,我們便認為客戶端與伺服器端斷開了連線;
  • PSH為1的情況,一般只出現在 DATA內容不為0的包中,也就是說PSH為1表示的是有真正的TCP資料包內容被傳遞。

關於SYN攻擊的理解:

SYN攻擊屬於DDOS(即分散式拒絕服務)的一種,

通過向目標主機發送大量的半連線請求(即SYN請求)並且偽裝源IP和源埠,

使目標主機響應繁複的響應情況中(由於源IP為虛假IP,即顯示中不存在,在目標主機迴應了SYN+ACK報文後,由於沒有等到請求主機的響應,目標主機啟動重傳機制,)

在反覆傳送後,達到一定的限制即放棄重發,使目標主機限於網路堵塞

三次握手過程:

一個虛擬連線的建立是通過三次握手來實現的

當客戶端B,向伺服器端A請求建立連線時:

1.兩端首先都處於close狀態;然後伺服器端A開啟,處於監聽狀態LISTEN,表示可建立連線。

2.然後B首先向A傳送一個SYN報文,並置報文中的標記SYN=1,傳送序號seq=X【這個X首次是隨機生成的】;然後B端進入SY_SENT狀態。

(此時報文中ACK標識,和ack確認號,沒有說明就是都為0)

3.A端正確接收到B端的這個報文後,向B端回覆一個對SYN報文的確認報文,即SYN+ACK報文,並置標記SYN和ACK都為1,傳送序號seq=Y【這個首次也是隨機生成的】,確認號ack=X+1;然後A端進入SYN_RCVD狀態

4.B端正確接收到A端返回的報文後,再向A端傳送一個ACK報文,通知A,連線已建立,並置其中標記ACK為1,傳送序號seq=X+1,確認號=Y+1;然後B端進入ESTABLISHED狀態

5.A端收到B傳送過來的報文後,也進入ESTABLISHED狀態

自此,客戶端進和伺服器通過TCP協議中的三次握手,建立好了連結。

當三此握手完成、連線建立以後,TCP連線的每個包都會設定ACK位

【再次梳理如下】

1. (B) –> [SYN] –> (A)

假如伺服器A和客戶機B通訊. 當A要和B通訊時

B首先向A發一個SYN (Synchronize) 標記的包,告訴A請求建立連線.

注意: 一個 SYN包就是僅SYN標記設為1的TCP包(參見TCP包頭Resources). 認識到這點很重要,

只有當A受到B發來的SYN包,才可建立連線,除此之外別無他法。

因此,如果你的防火牆丟棄所有的發往外網介面的SYN包,那麼你將不能讓外部任何主機主動建立連線。

2. (B) <– [SYN/ACK] <–(A)

接著,A收到後會發一個對SYN包的確認包(SYN/ACK)回去,表示對第一個SYN包的確認,並繼續握手操作.

注意: SYN/ACK包是僅SYN 和 ACK 標記為1的包.

3. (B) –> [ACK] –> (A)

B收到SYN/ACK 包,B發一個確認包(ACK),通知A連線已建立。

至此,三次握手完成,一個TCP連線完成

Note: ACK包就是僅ACK 標記設為1的TCP包.

需要注意的是當三此握手完成、連線建立以後,TCP連線的每個包都會設定ACK位

【舉例說明】

握手階段:

序號 方向 seq ack

1   A->B 10000 0

2 B->A 20000 10000+1=10001

3 A->B 10001 20000+1=20001

資料傳輸階段:

序號  方向   seq ack size

23 A->B 40000 70000 1514

24 B->A 70000 40000+1514-54=41460 54

25 A->B 41460 70000+54-54=70000 1514

26 B->A 70000 41460+1514-54=42920 54

握手階段解釋:

1:A向B發起連線請求,以一個隨機數初始化A的seq,這裡假設為10000,此時ACK=0

2:B收到A的連線請求後,也以一個隨機數初始化B的seq,這裡假設為20000,意思是:你的請求我已收到,我這方的資料流就從這個數開始。B的ACK是A的seq加1,即10000+1=10001

3:A收到B的回覆後,它的seq是B的ACK+1【大小就是它的上個請求的seq加1】,即10000+1=10001,意思也是:你的回覆我收到了,我這方的資料流就從這個數開始。A此時的ACK是B的seq加1,即20000+1=20001

資料傳輸階段解釋:

23:B接收到A發來的seq=40000,ack=70000,size=1514的資料包

24:於是B向A也發一個數據包,告訴B,你的上個包我收到了。

B的seq就以它收到的資料包的ACK填充,

ACK是它收到的資料包的SEQ加上資料包的大小(不包括乙太網協議頭,IP頭,TCP頭),

以證實B發過來的資料全收到了。

25:A在收到B發過來的ack為41460的資料包時,一看到41460,正好是它的上個數據包的seq加上包的大小,就明白,上次傳送的資料包已安全到達。

於是它再發一個數據包給B。

這個正在傳送的資料包的seq也以它收到的資料包的ACK填充,

ACK就以它收到的資料包的seq(70000)加上包的size(54)填充,即ack=70000+54-54(全是頭長,沒資料項)。

其實在握手和結束時確認號應該是對方序列號加1,

傳輸資料時則是對方序列號加上對方攜帶應用層資料的長度.

如果從乙太網包返回來計算所加的長度,就嫌走彎路了.

另外,如果對方沒有資料過來,則自己的確認號不變,

序列號為上次的序列號加上本次應用層資料傳送長度.

TCP的三次揮手過程分析:

建立一個連線需要3個步驟,但是關閉一個連線需要經過4個步驟。

因為TCP連線是全雙工的工作模式,所以每個方向上需要單獨關閉。

在TCP關閉連線時,首先關閉的一方(即傳送第一個終止資料包的)將執行主動關閉,而另一方(收到這個終止資料包的)再執行被動關閉。

關閉連線的4個步驟如下:

1.主動方傳送FIN+ACK報文,即報文中FIN標記和ACK標記都置為1;並且傳送序號seq=X,確認號ack=Z;【和SYN一樣,一個FIN將佔用一個序號】

【序列號為客戶端傳送的上一個資料包中的確認號值;

而確認號為伺服器傳送的上一個資料包中的序列號+該資料包所帶的資料的大小;】

2.被動方返回一個ACK報文,即報文中ACK標誌被置為1;並且傳送序號seq=Z(即上面接收到的確認號值),確認號ack=X+1(期待收到的下一個報文的序號);

3.被動方傳送一個FIN+ACK報文,傳送序號seq=Y,確認號ack=X【難以預測的ack】;

【序列號為伺服器傳送的上一個資料包中的確認號值,而確認號為客戶端發 送的上一個資料包中的序列號+該資料包所帶資料的大小】

4.主動方返回一個ACK確認報文,傳送序號seq=X,ack=Y+1

百度百科分析:

連線終止協議(四次揮手)

由於TCP連線是全雙工的,因此每個方向都必須單獨進行關閉。這原則是當一方完成它的資料傳送任務後就能傳送一個FIN來終止這個方向的連線。收到一個 FIN只意味著這一方向上沒有資料流動,一個TCP連線在收到一個FIN後仍能傳送資料。首先進行關閉的一方將執行主動關閉,而另一方執行被動關閉。

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

(2) 伺服器收到這個FIN,它發回一個ACK,確認序號為收到的序號加1。和SYN一樣,一個FIN將佔用一個序號。

(3) 伺服器關閉客戶端的連線,傳送一個FIN給客戶端。

(4) 客戶端發回ACK報文確認,並將確認序號設定為收到序號加1。

狀態分析

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連線,但另外還告訴對方,我暫時還有點資料需要傳送給你,稍後再關閉連線。【可能還會傳資料,因此ack的結果很難預測】

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可用狀態了。

相關問題:

1. 為什麼連線的時候是三次握手,關閉的時候卻是四次握手?

答:因為當Server端收到Client端的SYN連線請求報文後,可以直接傳送SYN+ACK報文。其中ACK報文是用來應答的,SYN報文是用來同步的。但是關閉連線時,當Server端收到FIN報文時,很可能並不會立即關閉SOCKET,所以只能先回復一個ACK報文,告訴Client端,"你發的FIN報文我收到了"。只有等到我Server端所有的報文都發送完了,我才能傳送FIN報文,因此不能一起傳送。故需要四步握手。

2. 為什麼TIME_WAIT狀態需要經過2MSL(最大報文段生存時間)才能返回到CLOSE狀態?

答:雖然按道理,四個報文都發送完畢,我們可以直接進入CLOSE狀態了,但是我們必須假象網路是不可靠的,有可以最後一個ACK丟失。所以TIME_WAIT狀態就是用來重發可能丟失的ACK報文。

3.

.

4.