天天看點

TCP的seq和ack号計算方法

seq和ack号存在于TCP封包段的首部中,seq是序号,ack是确認号,大小均為4位元組(注意與大寫的ACK不同,ACK是6個控制位之一,大小隻有一位, 僅當 ACK=1 時ack字段才有效。建立 TCP 連接配接後,所有封包段都必須把 ACK 字段置為 1。)

TCP的seq和ack号計算方法

seq:占 4 位元組,序号範圍[0,2^32-1],序号增加到 2^32-1 後,下個序号又回到 0。TCP 是面向位元組流的,通過 TCP 傳送的位元組流中的每個位元組都按順序編号,而報頭中的序号字段值則指的是本封包段資料的第一個位元組的序号。 ack:占 4 位元組,期望收到對方下個封包段的第一個資料位元組的序号。

1、三次握手過程中seq和ack的值:

一個TCP連接配接的建立是通過三次握手來實作的

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

假如伺服器B和客戶機A通訊. 當A要和B通信時,A首先向B發一個SYN (Synchronize) 标記的包,告訴B請求建立連接配接. 注意: 一個 SYN包就是僅SYN标記設為1的TCP包(參見TCP標頭Resources). 認識到這點很重要,隻有當B受到A發來的SYN包,才可建立連接配接,除此之外别無他法。是以,如果你的防火牆丢棄所有的發往外網接口的SYN包,那麼你将不能主動連接配接外部任何主機,除非不是TCP協定。 2. (A) <– [SYN/ACK] <–(B)

接着,B收到後會發一個對SYN包的确認包(SYN/ACK)回去,表示對第一個SYN包的确認,并繼續握手操作.

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

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

A收到SYN/ACK 包,A發一個确認包(ACK),通知B連接配接已建立。至此,三次握手完成,一個TCP連接配接完成

Note: ACK包就是僅ACK 标記設為1的TCP包. 需要注意的是當三此握手完成、連接配接建立以後,TCP連接配接的每個包都會設定ACK位 握手階段:

序号 方向 seq ack SYN ACK
1 A->B 10000 1
2 B->A 20000 10000+1=10001 1 1
3 A->B 10001 20000+1=20001 1

解釋: 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是它的上個請求的seq加1,即10000+1=10001,意思也是:你的回複我收到了,我這方的資料流就從這個數開始。A此時的ACK是B的seq加1,即20000+1=20001

2、資料傳輸過程中seq和ack的值:

序号 方向 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

解釋: 23:B接收到A發來的seq=40000,ack=70000,size=1518的資料包 24:于是B向A也發一個資料包,告訴A,你的上個包我收到了。A的seq就以它收到的資料包的ack填充,ack是它收到的資料包的seq加上資料包的大小(不包括:以太網協定頭=14位元組,IP頭=20位元組,TCP頭=20位元組),以證明B發過來的資料全收到了。 25:A在收到B發過來的ack為41460的資料包時,一看到41460,正好是它的上個資料包的seq加上包的大小,就明白,上次發送的資料包已安全到達。于是它再發一個資料包給B。這個正在發送的資料包的seq也以它收到的資料包的ack填充,ack 就以它收到的資料包的seq(70000)加上包的size(54)填充,即ack=70000+54-54(全是頭長,沒資料項)。

減去54的原因見下圖(鍊路層使用的是Ethernet II 格式,這個格式有14位元組以太網首部+4位元組以太網尾部): 應用資料=size-14-20-20=size-54。(假設IP首部和TCP首部都沒有可選選項) 為什麼不減去以太網尾部的4位元組呢? 因為在實體層上網卡要先去掉前導同步碼和幀開始定界符,然後對幀進行CRC檢驗,如果幀校驗和錯,就丢棄此幀。如果校驗和正确,就判斷幀的目 的硬體位址是否符合自己的接收條件(目的位址是自己的實體硬體位址、廣播位址、可接收的多點傳播硬體位址等),如果符合,就将幀交“裝置驅動程式”做進一步處 理。這時我們的抓包軟體才能抓到資料,是以,抓包軟體抓到的是去掉前導同步碼、幀開始分界符、FCS之外的資料,

TCP的seq和ack号計算方法

3、四次揮手過程中seq和ack的值:

TCP連接配接的結束是四次揮手的過程,ACK一直等于1

序号 方向 seq ack FIN ACK
1 A->B 80000 90000 1 1
2 B->A 90000 80000+1=80001 1
3 B->A 95000 80001 1 1
4 A->B 80001 95000+1=95001 1

1. (A) –> [FIN/ACK] –> (B) 用戶端A沒有要發送給服務端B的資料了,想要關閉連結,則發送一個FIN=1,ACK=1的包,告訴B可以關閉連接配接了,我沒有什麼資料要給你了。 2. (A) <– [ACK] <– (B) 然後B會發送ACK=1的包給A,告訴A我知道你沒有什麼想給我的了,但是我還有資料要給你,你先等下,我先不想FINISH呢。 3. (A) <– [FIN/ACK] <– (B) 等B把資料都發送給A之後,B會再次發送一個包,這次FIN=1,表示我這邊也想關閉了,咱倆一起關把。在2和3之間,可能還會有很多B->A的傳遞,ack均為80001。 4. (A) –> [ACK] –> (B) 然後A回應一個ACK,表示我知道了,一起關吧。B收到這個ACK後,就會CLOSE。但是實際上A不會直接CLOSE,還會進入一個等待時間狀态TIME_WAIT,持續2倍的MSL(Maximum Segment Lifetime,封包段在網絡上能存活的最大時間)。過了這個狀态,才會CLOSE。為什麼要等待一段時間?原因有二: (1)保證TCP的全雙工連接配接能夠可靠關閉 假如A發送的最後一次ACK丢包了,沒有被B收到,那B逾時之後,會再次發送一個FIN包,然後這個包被處于TIME_WAIT狀态的A收到,A會再次發送一個ACK包,并重新開始計時,一直循環這個過程,直到A在TIME_WAIT的整個過程中都沒有收到B發過來的FIN包,這說明B已經收到了A的ACK包并CLOSE了,是以A這時候才可以安心CLOSE。如果A沒有TIME_WAIT狀态而是直接close,那麼當ACK丢包之後,B會再次發送一個FIN包,但是這個包不會被A回應,是以B最終會收到RST,誤以為是連接配接錯誤,不符合可靠連接配接的要求。是以需要等待ACK封包到達B+BRST是TCP資料報中6個控制位之一,6個控制位的作用如下: URG 緊急:當 URG=1 時,它告訴系統此封包中有緊急資料,應優先傳送(比如緊急關閉),這要與緊急指針字段配合使用。 ACK 确認:僅當 ACK=1 時确認号字段才有效。建立 TCP 連接配接後,所有封包段都必須把 ACK 字段置為 1。 PSH 推送:若 TCP 連接配接的一端希望另一端立即響應,PSH 字段便可以“催促”對方,不再等到緩存區填滿才發送。 RST複位:若 TCP 連接配接出現嚴重差錯,RST 置為 1,斷開 TCP 連接配接,再重建立立連接配接。 SYN 同步:用于建立和釋放連接配接,稍後會詳細介紹。 FIN 終止:用于釋放連接配接,當 FIN=1,表明發送方已經發送完畢,要求釋放 TCP 連接配接。 (2)保證這次連接配接的重複資料段從網絡中消失 如果A直接close了,然後向B發起了一個新的TCP連接配接,可能兩個連接配接的端口号相同。一般不會有什麼問題,但是如果舊的連接配接有一些資料堵塞了,沒有達到B呢,新的握手連接配接就已經到B了,那麼這時候,由于區分不同TCP連接配接是依據套接字,是以B會将這批遲到的資料認為是新的連接配接的資料,導緻資料混亂(源IP位址和目的IP位址以及源端口号和目的端口号的組合稱為套接字,新舊連接配接的套接字很有可能相同)

總結: 确認号: 在握手和結束時确認号應該是對方序列号加1,傳輸資料時則是對方序列号加上對方攜帶應用層資料的長度,如果對方攜帶應用層資料長度為0,則ack與對方序列号相同,不要+1,比如25的ack與24的seq相同。也可以這樣了解,因為24沒有發送資料,是以A期待B下次發送過來的第一個位元組的序号不變,是以25的ack與23的ack相同。 序列号: 在握手和結束時序列号應該是上次序列号+1,傳輸資料時則是上次的序列号加上上次應用層資料發送長度,如果資料長度為0,則seq與上次一樣,不要+1,比如26的seq和24的seq相同。