三次握手過程中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包,才可建立連接,除此之外別無他法。
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連接完成
注意: 需要注意的是當三此握手完成、連接建立以后,TCP連接的每個包都會設置ACK位
握手階段的ack和seq值變化:
對上表的解釋:
1:A向B發起連接請求,以一個隨機數初始化A的seq,這里假設為10000,此時ACK=0,ack無意義
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
傳輸過程中seq和ack值
三次握手建立連接之后,就開始傳輸數據了
取中間一段的傳輸過程舉例
對上表的解釋:
23:B接收到A發來的seq=40000,ack=70000,size=1518的數據包
24:於是B向A也發一個數據包,告訴A,你的上個包我收到了。此時B的seq就是它收到的數據包A的ack,B的ack是它收到的數據包的seq加上該數據包的大小(不包括:
以太網協議頭=14字節,IP頭=20字節,TCP頭=20字節),以證實B發過來的數據全收到了。
25:A在收到B發過來的ack為41460的數據包時,一看到41460,正好是它的上個數據包的seq加上包的大小,就明白,上次發送的數據包已安全到達。
於是它再發一個數據包給B。此時A正在發送的數據包的seq就等於它收到的數據包的ack填充,A的ack 就等於它收到的數據包的seq(70000)加上包的size(54)填充,
即ack=70000+54-54(全是頭長,沒數據項)。
為什么要減去54?
鏈路層使用的是Ethernet II 格式,這個格式有14字節MAC幀首部+4字節MAC幀尾部,還有TCP數據報和IP數據報的首部各20個字節):
應用數據=size-14-20-20=size-54。(假設IP首部和TCP首部都沒有可選選項)
為什么不減去MAC幀尾部的4字節呢?
因為在物理層上網卡要先去掉前導同步碼和幀開始定界符,然后對幀進行CRC檢驗,如果幀校驗和錯,就丟棄此幀。如果校驗和正確,就判斷幀的目 的硬件地址是否符合自己的接收條件(目的地址是自己的物理硬件地址、廣播地址、可接收的多播硬件地址等),如果符合,就將幀交“設備驅動程序”做進一步處 理。這時我們的抓包軟件才能抓到數據,因此,抓包軟件抓到的是去掉前導同步碼、幀開始分界符、FCS之外的數據,
四次揮手過程中seq和ack值
終止字符(FIN): 值為1表示要發送的數據報已經發送完畢,需要釋放傳送連接。
1. (A) –> [FIN/ACK] –> (B)
客戶端A沒有要發送給服務端B的數據了,想要關閉鏈接,則發送一個FIN=1,ACK=1的包,告訴B可以關閉連接了,我沒有什么數據要給你了。
此時A的狀態由ESTAB-LISHED變為FIN-WAIT1狀態
2. (A) <– [ACK] <– (B)
然后B會發送ACK=1的包給A,告訴A我知道你沒有什么想給我的了,但是我還有數據要處理完,你先等下。此時B的狀態由ESTAB-LISHED變為CLOSE-WAIT
3. (A) <– [FIN/ACK] <– (B)
過了一會,服務端處理完數據發送給客戶端[FIN/ACK],表明已經處理完數據,最后一次確認是否要准備關閉B->A的通信連接
4. (A) –> [ACK] –> (B)
然后A回應一個ACK,表示確認。B收到這個ACK后,就會CLOSE。但是A不會直接CLOSE,還會進入一個等待時間狀態TIME_WAIT,持續2倍的MSL(Maximum Segment Lifetime,報文段在網絡上能存活的最大時間,4分鍾)。過了這個狀態,才會CLOSE。
A為什么要等待一段時間,也就是TIMW-WAIT的作用?原因有二:
(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報文到達
(2)保證這次連接的重復數據段從網絡中消失
如果A直接close了,然后向B發起了一個新的TCP連接,可能兩個連接的端口號相同。一般不會有什么問題,但是如果舊的連接有一些數據堵塞了,沒有達到B呢,新的握手連接就已經到B了,那么這時候,由於區分不同TCP連接是依據套接字,因此B會將這批遲到的數據認為是新的連接的數據,導致數據混亂(源IP地址和目的IP地址以及源端口號和目的端口號的組合稱為套接字,新舊連接的套接字很有可能相同)
TIME_WAIT的作用(對應上面兩點)
1 需要服務端可靠地終止連接,如果處於time_wait客戶端發給服務端的ack報文丟失,則服務端會再發一次fin,此時客戶端不應該關閉。
2 保證遲來的tcp報文有時間被丟棄,因為2msl里超時抵達的報文都會被丟棄。
注意:TIME_WAIT是主動關閉連接的一方保持的狀態
總結
確認號:
在握手和結束時確認號應該是對方序列號加1,傳輸數據時則是對方序列號加上對方攜帶應用層數據的長度,如果對方攜帶應用層數據長度為0,則ack與對方序列號相同,不要+1,比如25的ack與24的seq相同。也可以這樣理解,因為24沒有發送數據,所以A期待B下次發送過來的第一個字節的序號不變,因此25的ack與23的ack相同。
序列號:
在握手和結束時序列號應該是上次序列號+1,傳輸數據時則是上次的序列號加上上次應用層數據發送長度,如果數據長度為0,則seq與上次一樣,不要+1,比如26的seq和24的seq相同。
以上部分轉載自https://blog.csdn.net/happyrocking/article/details/78198776