TCP 滑動視窗 與視窗縮放因子(Window Scaling)
一、前言
說道TCP滑動視窗協議,相信大家都很熟悉,但是說道 Window Scaling引數或許知道的和用過的人卻不多,本文我們來談談Window Scaling的由來
二、TCP滑動視窗
眾所周知,TCP是一種面向連線可靠訊息傳輸協議;為了保證可靠,連線的兩端保持對所有傳輸資料的嚴格跟蹤,以便在需要時候進行重傳或重新排序。另外為了跟蹤已經發送了的資料在傳送端有TCP傳送快取,在接受端有接受快取,滑動視窗則是這個快取的一部分,接收方接受資料後會把ack和當前滑動視窗可用空間告訴傳送方,傳送方則傳送的資料不能超過接收方剩餘視窗大小,如果接收方視窗內資料還沒來得及由應用程式讀取,視窗滿了,則傳送方會停止傳送資料,直到接收方滑動視窗有空間。
假設我們有兩個主機A和B,它們建立了一個TCP連線。在連線開始時,兩個主機為傳入資料分配32 KB的緩衝區空間,因此每個主機的初始視窗大小為32,768。
主機A需要向主機B傳送資料,一開始則主機B告訴主機A可以在自己接受主機B確認之前傳輸最多32,768位元組的資料(以最大段大小或MSS的間隔) 。假設MSS為1460位元組,主機A可以在耗盡主機B的接收視窗之前傳送22個段。
當確認收到主機A傳送的資料時,主機B可以調整其視窗大小。例如,如果上層應用程式僅處理了一半緩衝區,則主機B會將其視窗大小降低到16 KB(這時候主機A在接受到B的確認前最多傳送16KB資料到B)。如果緩衝區仍然完全填滿,主機B會將其視窗大小設定為零,表明它還不能接受更多資料,這時候主機A則停止傳送資料。
在具有高頻寬和極低延遲的LAN上,滑動視窗很少會空閒。但是,在高頻寬,高延遲網路上,會出現一個有趣的現象:在傳送方接受到接收方發出確認之前,並不能最大化利用滑動視窗大小。
例如,假設在通過專用10 Mbps路徑連線的兩臺主機之間建立TCP連線,單向延遲為80ms。兩個主機都約定最大視窗大小為65,535位元組(16位無符號整數的最大值)。我們可以計算在一個時間點在一個方向上傳輸的潛在資料量,頻寬*延遲:10,000,000 bps除以每位元組8位,乘以0.08秒等於100,000位元組。
換句話說,如果主機A開始連續傳送給主機B,它將在主機B接收到傳送的第一個位元組之前傳送100,000個位元組。但是由於約定的最大接收視窗只有65,535位元組,所以主機A必須在傳送65,535位元組後停止傳送,並等待來自主機B的確認。(為簡單起見,我們的示例計算不考慮TCP和低層報頭。)這種延遲浪費了潛在的吞吐量,不必要地增加了通過網路可靠傳輸資料所需的時間。建立TCP視窗縮放以解決此問題。
在應用實戰中,我們的檔案上傳服務上傳圖片時候還好,但是上傳大視訊時候就發現很慢,一個8M的視訊上傳需要1分鐘30s,我們載入tcpbuffer和開啟了縮放因子調優後,8M視訊只需要20s。
三、視窗縮放因子
視窗縮放在RFC 1072中引入並在RFC 1323中進行了改進。實際上,視窗縮放只是將16位視窗欄位擴充套件為32位長度。解決方案是定義TCP選項以指定計數,通過該計數,TCP標頭欄位應按位移位以產生更大的值。
如上圖 window size設定為5840位元組,但是視窗縮放因子為7(window scale),也就是這時候最大實際視窗為 5840*128。window scale為1將欄位的二進位制值向左移位一位,使其加倍。計數為2將值向左移動兩位,使其翻倍。計數為7(如上例所示)將該值乘以128.
視窗縮放選項(window scaleing)可以在tcp握手時候在SYN分組中的連線期間僅傳送一次。可以通過修改TCP標頭中的視窗欄位的值來動態調整視窗大小,但是在TCP連線的持續時間內,標度乘數保持靜態。僅當兩端都包含選項時,縮放才有效;如果只有連線的一端支援視窗縮放,則不會在任一方向上啟用它。最大有效比例值為14(RFC 1323的2.3節為有興趣的人提供了一些背景資訊)。
回顧我們之前的示例,我們可以觀察視窗縮放如何使我們能夠更有效地進行網路傳輸。為了計算我們的理想視窗,我們將端到端延遲加倍以找到往返時間,並將其乘以可用頻寬:2 * 0.08秒* 10,000,000 bps / 8 = 200,000位元組。為了支援這種大小的視窗,主機B可以將其視窗大小設定為3,125,其window scaleing因子為6(3,125左移6乘以200,000)。幸運的是,這些計算都是由現代TCP / IP堆疊實現自動處理的。
四、參考
http://packetlife.net/blog/2010/aug/4/tcp-windows-and-window-scaling/