為什麼TCP的MSS協商沒有按照小的來?

如下圖,我看到握手協商的時候,本機MSS是1460,而服務端返回是1452,但是最終在發送數據的時候,我發現本機發出的數據還是按照1460來發送的,乙太網幀都是1514的大小,看了很多資料都說是按照MSS小的來,不是很明白為什麼沒有理會服務端的MSS,如果本機任然按照MSS 1460來發送,最終的乙太網幀payload就是1500,如果對方MTU是1492,那麼是不是在對方會進行拆包?多謝各位


首先,我要糾正題主的描述,1514位元組的TCP報文是伺服器發過來的,而不是客戶端發出的。

MSS是TCP option 4,option意思是可選項,不強制要求,意思是,通信雙方並不一定honor對方的MSS size選擇。

如果尊重對方的選擇,避免分片,那是最理想的選擇!

一種情況
伺服器端發出的包到達客戶端並沒有分片,說明伺服器到客戶端的物理路徑上MTU應該不會小於1500,可見伺服器端的MSS是配置成的1452,而不是預設辦法,即物理介面(MTU-IP頭長度-TCP頭長度)= 1500-20-20= 1460,一般伺服器介面不會配成1492的。

第二種情況
如果客戶端是PPPoE接入,一定會發生分片,而捕獲的報文里沒有看到分片,說明分片已經被網卡重組過之後,才將重組後的IP包複製給wireshark。

基本上就以上兩種情況。


這個問題不那麼好回答。因為有歷史遺留因素和具體實現差異。

首先明確一點,MSS確實是雙向獨立的,兩邊的MSS可以不同。

MSS本身是一個TCP選項,理應只為TCP本身負責而不用對下層IP或者鏈路層協議負責。當初設計這個參數只是為了考慮雙方TCP協議棧的buffer大小的,所以客戶和伺服器端可以分別針對自己buffer大小設置自己的MSS。但是在協議棧實現中,要考慮因為MSS過大導致在IP層分片的情況,於是MSS就被實現成到了MTU減去包頭大小。這樣實際上MSS不光是TCP本身的一個參數,還要考慮下面的網路層和鏈路層情況了。

但是僅此還不夠。在Internet上,還存在來去流量走不同鏈路的問題,導致需要分別考慮兩端的MSS。還有更討厭的事情,是客戶端伺服器本身MSS確定後,發生在鏈路傳輸過程中中間設備MTU過小導致的分片。這一堆實際問題就催生了不同的MSS實現,以及協議棧實現中的額外的附加功能,例如PMTUD。

Cisco有篇文總結的不錯,建議作為參考看看。討論了不少需要考慮的情況:

Resolve IP Fragmentation, MTU, MSS, and PMTUD Issues with GRE and IPSEC


有超過MTU大小的包被抓取,有可能網卡LSO功能被打開。也可見我之前的問題tcp 握手後向公網發送包,與mss大小不符合,丟失問題?,或許相似,可以參考


MSS是端到端的TCP通告,客戶端和百度伺服器各自通告MSS後,拿到較小值,在TCP協議棧做segmentation的時候就會按照這個值往二層寫。如果是開啟了gso/tso/gro等,這個segmenation的工作被offload到網卡上。

tcpdump抓到的包只是在網卡驅動層面看到的數據封裝情況,如果segmentation offload到網卡,則tcpdump看到的內容不是實際在Internet上的封裝結構。

你看看你使用的客戶端是什麼系統,有沒有做發包和收包的offload。

如下是Linux裡面的抓包,是正常的。

$ sudo ethtool -K eth0 gso off
$ sudo ethtool -K eth0 tso off
$ sudo ethtool -K eth0 gro off

tcpdump如下,length是1452 (1506-14-40).

1 0.000000 172.31.3.22 → 61.135.169.121 TCP 74 41738→443 [SYN] Seq=0 Win=29200 Len=0 MSS=1460 SACK_PERM=1 TSval=1571421967 TSecr=0 WS=128
2 0.001437 61.135.169.121 → 172.31.3.22 TCP 74 443→41738 [SYN, ACK] Seq=0 Ack=1 Win=8192 Len=0 MSS=1452 SACK_PERM=1 WS=32
3 0.001448 172.31.3.22 → 61.135.169.121 TCP 54 41738→443 [ACK] Seq=1 Ack=1 Win=29312 Len=0
4 0.088178 172.31.3.22 → 61.135.169.121 SSL 248 Client Hello
5 0.090099 61.135.169.121 → 172.31.3.22 TCP 54 443→41738 [ACK] Seq=1 Ack=195 Win=25856 Len=0
6 0.090111 61.135.169.121 → 172.31.3.22 TLSv1.2 150 Server Hello
7 0.090117 172.31.3.22 → 61.135.169.121 TCP 54 41738→443 [ACK] Seq=195 Ack=97 Win=29312 Len=0
8 0.090126 61.135.169.121 → 172.31.3.22 TCP 1506 [TCP segment of a reassembled PDU]
9 0.090131 172.31.3.22 → 61.135.169.121 TCP 54 41738→443 [ACK] Seq=195 Ack=1549 Win=32128 Len=0
10 0.090133 61.135.169.121 → 172.31.3.22 TCP 1506 [TCP segment of a reassembled PDU]
11 0.090136 172.31.3.22 → 61.135.169.121 TCP 54 41738→443 [ACK] Seq=195 Ack=3001 Win=35072 Len=0
12 0.090141 61.135.169.121 → 172.31.3.22 TCP 1506 [TCP segment of a reassembled PDU]
13 0.090144 172.31.3.22 → 61.135.169.121 TCP 54 41738→443 [ACK] Seq=195 Ack=4453 Win=38016 Len=0
14 0.090145 61.135.169.121 → 172.31.3.22 TLSv1.2 463 Certificate


自己測了一下,看起來MSS並不是雙向相同的,client的MSS是1460,server的MSS是1452,那麼client的乙太網幀大小是1508,而server回傳是1514,client按照server的MSS發包,而server按照client的MSS發包,不知道為什麼會這樣,如果server的MTU是1492,那麼server發的包豈不是還要拆包?為什麼大家不按照MSS 1452傳呢?


推薦閱讀:

關於IP數據報轉發的疑問?
個人計算機裡面包含網路7層協議的所有協議嗎,每一層分別對應哪個部分?
交換機mac表的獲取?
rip,ospf屬於應用層協議,但是路由器只是工作在下三層啊,網路層,數據鏈路層,以及物理層,這怎麼解釋啊?
關於IP分組的分段是什麼原理?

TAG:計算機科學 | TCPIP |