當前位置:
首頁 > 最新 > TCP 的ACK跳號、SEQ跳號是怎麼回事?

TCP 的ACK跳號、SEQ跳號是怎麼回事?

感謝為此文提出寶貴點評的朋友們!

以下斜體部分為讀者提問:

題主寫了一個簡單的C++裸socketC/S測試程序:

其中Server監聽6666埠,Client一次性send5M的文本數據到Server,但Server故意只recv一次後sleep 60秒後close掉fd。

期間啟動tcpdump監聽6666埠,tcpdump命令為tcpdump -nn -vvv -i any tcp port 6666。

有3個很奇怪的問題:(lro/gro/gso/tso均已關閉off)

1、固定length:我測試了不同的機器,發送的length很固定,一直都是21845(21kb),我查遍了系統內和網路以及socket相關的緩衝區大小,都和21845無任何關係,不知原因。

求大神賜教,提供解決方案也行。

當匪夷所思的事情發生時莫慌,拿出懷疑一切的精神與態度,用放大鏡來檢查每一個報文,以下是我的檢測報告。

第一個問題:TCP Segment Length = 21845 怎麼得來的?

客戶端:172.16.8.83:42511

伺服器:172.16.8.83:6666

這是同一台主機上不同進程之間的通信,進程之間的通信,在TCP/IP協議棧內部(loop)完成,不會流動到硬體網卡,所以不受硬體網卡MTU =1500的限制。

進程間的通信TCP報文的尺寸受什麼限制?

(1)IP報文的最大尺寸(本地限制)

眾所周知,IP報文頭部Length的長度為2個位元組,IP報文最大尺寸為65535

TCP的最大報文尺寸MSS= 65535 -20位元組IP頭-20位元組TCP頭 =65495

這點可以通過TCP三次握手的第一、二個報文清晰地看出。

有同學會問,既然雙方協商的MSS =65495,那為何客戶端不使用65495來傳輸數據?

且慢,TCP發送方發送的報文還受到接收端window的限制。

(2)對端Advertised Window Size (對端限制)

從三次握手的第二個報文可以知道,接收端(伺服器)advertised window size =43690。

取兩個限制條件中最小值,這個很好理解吧?

客戶端一次最大能發送的TCP Segment Length =43690

為何客戶端選擇了21845 而不是43690?

計算了一下,43690/2 = 21845,意味著客戶端只選擇最大發送長度的一半來發送自己的數據,為了讓伺服器儘快通知應用程序取走數據,每2個TCP報文會設置P標誌位,P標誌位是Push的縮寫。

客戶端深深地知道,伺服器的接收緩衝區只有43690位元組大小,發送2個segment(21845),恰好將緩衝區佔滿,這時如果應用程序不儘快取走數據,伺服器端的advertise window size 將等於0。客戶端收到伺服器端window=0 通知之後,會停止一切數據發送工作,這將嚴重影響TCP發送性能。

剩下的2個問題,其實是一個問題,因為都是同樣的原因造成的。

第二個問題:為何ACK Number 、Sequence Number會跳號?

大家看第一個TCPDUMP抓包圖片的中部位置:

兩者ID差值 = 56838 -56823 =15

兩者SEQ差值 = 720886-393211 =327675

兩者之間有何聯繫呢?

15 * 21845 = 327675

我的懷疑是,從56823、56824、56825 。。。56836、56837共14個segment被伺服器成功接收,但是卻被TCPDUMP程序漏掉了。

如果伺服器沒有收到,自然不會確認,客戶端會重傳,可是抓包里並沒有。

第二個捕獲圖片里的問題和這個一樣,也是報文到達對方,卻被TCPDUMP無情漏掉了,才會有跳號的疑惑。

接下來談談關於TCP/IP更多的發現。

IP頭部ID

同一個TCP Session, IP頭部的ID每次遞增1,而不是動態隨機的,這樣做最大的好處是便於排錯,我正是利用了ID遞增規律,發現隱藏的事實。

TCP Window Scale 選項

TCP連接握手時,一共協商了四個option:

MSS/ SACK / Timestamp / Window Scale

接下來重點討論Window Scale(WS)

在沒有開啟WS選項的情況下,TCP通告的window size最大為65535,什麼意思呢?

發送方在沒有得到接收方的ACK確認前,最多只能傳輸65535位元組,傳完就只有耐心地等待接收方的ACK以及window更新。等待的時間和RTT成正比,如果RTT很大(傳輸距離很遠),也意味著發送方停止發送的時間也越長,這將嚴重影響長途傳輸、且帶寬很高的管道的TCP傳輸性能。我們通常稱這種管道為長肥管道,對應的英文為「Long, Fat Network」 (LFN)

為了提高長肥管道的TCP性能,提出了擴大window size的意見,但是window 佔據的只有兩個位元組,如何擴大呢?

依靠Window Scale,在雙方SYN/SYN+ACK握手時,雙方聲明支持該option,以及這個window scale的大小,在這個問題里window scale =7

Window Scale =7 是什麼意思?

27= 128

這個128稱為放大因子

通告方有128000位元組的接收緩衝區,window = Receive Buffer/WS = 128000/128= 1000,通告window= 1000。

接收方接到了window =1000如何處理呢?

只要把接收到的window 乘以放大因子,即這裡的128,就可以得到對方的真實window = 1000*128 =128000。

但windowscale只針對非握手報文有效,對握手報文(SYN/SYN=ACK)不起作用

WS選項只能通過SYN/SYN+ACK來協商,任何非SYN報文攜帶WS選項,一律無效。

用以上的文字來分析這個問題TCP捕獲文件。

TCP第一、二個為握手報文,雙方聲明自己支持window scale,放大因子都為128。

此時雙方通告的window = 43690,這個window就是雙方真實的window,不需要乘128。

第三個報文為客戶端ACK伺服器的握手報文,此時window =342,真實window 需要乘以放大因子,此時真實window = 342 *128 = 43776

第六個報文為伺服器確認客戶端的ACK報文,此時window =1365,真實window = 1365*128= 174720

第七個報文為伺服器確認客戶端的ACK報文,此時window = 2388,真實window = 2388 *128 = 305664,意味著客戶端在沒有得到伺服器進一步ACK之前,最多可以發多少個報文呢 ?

305664/21845 = 14.22

可以連續發14個!

在連續發送11個的時候,伺服器已經開始確認了,並更新了window = 3411,真實window = 3411* 128 = 436608

意味著客戶端可以連續發送更多的報文,壓根不會有停止等待的時候,這樣不停歇的傳輸方式肯定優於 「發發停停」的傳輸方式。

WindowScale 的意義

64K的window已經成為網路傳輸的瓶頸,網路管道大多數時候處於空閑狀態。為了充分利用帶寬,最直接的方法就是用待傳輸位元組填充網路管道,使其一直處於繁忙狀態。通過WS選項,最大可以將64K window放大214= 16384倍。

Maximum Window = 64K * 16K =1G

意味著在沒有得到對方任何確認的情況下,可以連續發送1G位元組,將端到端的網路管道塞得滿滿的,達到最大效率利用帶寬的效果。

如果喜歡這篇文章,請轉發給您身邊的朋友閱讀,這是對我最大的讚賞支持,謝謝!

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 全球大搜羅 的精彩文章:

「閉合形」與「開放形」的視覺空間表象淺析
不對著地漏如何裝淋浴房

TAG:全球大搜羅 |