TCP報文一次性最大運輸的貨物量(Payload),大體可以這么來計算:
IP報文頭長度 + TCP報文頭長度 + Payload長度 ≤ MTU
即左邊的三者之和,要小於等於右邊MTU的長度,其中:
Internet 路由器接口標准MTU = 1500
IP報文頭長度 = 20
TCP報文頭長度 = 20
所以
Payload長度≤ MTU – IP報文頭長度 – TCP報文頭長度
≤ 1500 -20 -20
≤ 1460
TCP為了提高傳輸效率,通常會使用最大上限1460字節來傳輸應用層數據,如http,除非http待傳輸數據小於1460。
但是TCP沒有那么簡單,所以還需要考慮得更多一點。
TCP報文通常有3部分組成:IP Header + TCP Header + Payload
但是,當前主流操作系統的TCP/IP協議棧,為了提高傳輸性能,通常還會使用 TCP Option選項。
一個例子
客戶端在TCP握手連接,告訴服務器自己支持以下三個option:
(1) Maximum Segment Size
(2) SACK Permitted
(3) Timestamp
服務器接收到該報文,卻有不同的意見,服務器只支持這三者中的Maximum Segment Size
Option,翻譯成中文是選項。所謂選項,不是強制標准,對方如果不支持或不理解,完全可以忽略。
在這里服務器並沒有打算支持選項2 ,3, 所以雙方共同支持雙方的交集,即選項1。
Maximum Segment Size
MSS的存在是為了通信雙方交換各自TCP Payload最大傳輸長度,這個長度上限一般為1460,即上文計算的方法。
如果雙方的MSS不一樣,將選擇較小的MSS值,作為接下來通信Payload的長度上限。
假如服務器支持選項2,“Timestamp”,那么TCP報文將會包含4部分:
IP Header + TCP Header + TCP Option +Payload
這里的TCP Option為“Timestamp”,長度為 10字節,看看 Payload最大可以傳輸多少字節?
IP Header + TCP Header + TCP Option +Payload ≤ 1500
IP Header + TCP Header + Timestamp +Payload ≤ 1500
Payload ≤ 1500 - IP Header -TCP Header – Timestamp
≤ 1500 -20 -20 -10
≤ 1450
簡而言之,沒有攜帶option的TCP報文,最大可以支持1460字節的Payload長度。
一旦攜帶option,由於option需要占用空間,留給payload的空間將會相應減少,具體減少的空間等於option占用的空間。
Payload長度和Window Size有關系嗎?
有一點點關系。
如果把Payload 1460看成一個標准的集裝箱,Window Size可以看作雙方的倉庫大小,用於臨時堆放對方運過來的集裝箱,在集裝箱被客戶運走之前,一直會呆在TCP倉庫里。
為了更高效地利用倉庫,最理想的方法就是,倉庫的大小是集裝箱的整數倍,這樣就不會產生零星的空間。
零星的空間一直無法使用,因為不夠容納一個標准集裝箱,勢必會造成倉庫空間的浪費。
空間浪費只是直接后果,還有一個間接后果,更加嚴重。
假設接收方的倉庫空間還有200字節,於是通過window size update消息告訴發送方。
發送方心急火燎發200字節,那么一個標准1460報文,將會分成8個小報文發送,這樣的傳輸效率會非常低下。
為了避免這種低效傳輸場景,TCP協議有了新的嚴格規定:
如果 window size < MSS , 不允許更新自己的window。
上文用通俗語言表達為,一旦接收方的倉庫空間小於一個標准集裝箱,window size update = 0 , 即善意欺騙對方,倉庫已經用完,不允許再發貨物過來。
以上是從接收方入手,萬一接收方沒有遵守規定,那就讓發送方嚴格執行另外一個規定。
發送方一旦發現對方的window size < MSS,理解為對方的倉庫已經占滿(剩余空間不足以容納一個標准集裝箱),不會發送任何集裝箱。