1. 程式人生 > >TCP的seq和ack號計算方法

TCP的seq和ack號計算方法

seq和ack號存在於TCP報文段的首部中,seq是序號,ack是確認號,大小均為4位元組(注意與大寫的ACK不同,ACK是6個控制位之一,大小隻有一位, 僅當 ACK=1 時ack欄位才有效。建立 TCP 連線後,所有報文段都必須把 ACK 欄位置為 1。)
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位握手階段:
序號方向seqackSYNACK
1A->B10000010
2B->A2000010000+1=1000111
3A->B1000120000+1=2000101
解釋: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=200012、資料傳輸過程中seq和ack的值:
序號方向seqacksize
23A->B40000700001514
24B->A7000040000+1514-54=4146054
25A->B4146070000+54-54=700001514
26B->A7000041460+1514-54=4292054
解釋: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之外的資料
3、四次揮手過程中seq和ack的值:TCP連線的結束是四次揮手的過程,ACK一直等於1
序號方向seqackFINACK
1A->B800009000011
2B->A9000080000+1=8000101
3B->A950008000111
4A->B8000195000+1=9500101
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相同。