一、前言

說道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上,滑動窗口很少會full。但是,在高帶寬,高延遲網路上,會出現一個有趣的現象:在發送方接受到接收方發出確認之前,並不能最大化利用滑動窗口大小。

例如,假設在通過專用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堆棧實現自動處理的。

四、參考

packetlife.net/blog/201


推薦閱讀:
相关文章