1. 程式人生 > >網路基本功(八):細說TCP滑動視窗

網路基本功(八):細說TCP滑動視窗

介紹

將TCP與UDP這樣的簡單傳輸協議區分開來的是它傳輸資料的質量。TCP對於傳送資料進行跟蹤,這種資料管理需要協議有以下兩大關鍵功能:

可靠性:保證資料確實到達目的地。如果未到達,能夠發現並重傳。

資料流控:管理資料的傳送速率,以使接收裝置不致於過載。

要完成這些任務,整個協議操作是圍繞滑動視窗確認機制來進行的。因此,理解了滑動視窗,也就是理解了TCP。

更多資訊

TCP面向流的滑動視窗確認機制:

TCP將獨立的位元組資料當作流來處理。一次傳送一個位元組並接收一次確認顯然是不可行的。即使重疊傳輸(即不等待確認就傳送下一個資料),速度也還是會非常緩慢。

image002.jpg

TCP訊息確認機制如上圖所示,首先,每一條訊息都有一個識別編號,每一條訊息都能夠被獨立地確認,因此同一時刻可以傳送多條資訊。裝置B定期傳送給A一條傳送限制引數,制約裝置A一次能傳送的訊息最大數量。裝置B可以對該引數進行調整,以控制裝置A的資料流。

為了提高速度,TCP並沒有按照位元組單個傳送而是將資料流劃分為片段。片段內所有位元組都是一起傳送和接收的,因此也是一起確認的。確認機制沒有采用message ID欄位,而是使用的片段內最後一個位元組的sequence number。因此一次可以處理不同的位元組數,這一數量即為片段內的sequence number。

TCP資料流的概念劃分類別

假設A和B之間新建立了一條TCP連線。裝置A需要傳送一長串資料流,但裝置B無法一次全部接收,所以它限制裝置A每次傳送分段指定數量的位元組數,直到分段中已傳送的位元組數得到確認。之後,裝置A可以繼續傳送更多位元組。每一個裝置都對傳送,接收及確認資料進行追蹤。

如果我們在任一時間點對於這一過程做一個“快照”,那麼我們可以將TCP buffer中的資料分為以下四類,並把它們看作一個時間軸:

1.    已傳送已確認 資料流中最早的位元組已經發送並得到確認。這些資料是站在傳送裝置的角度來看的。如下圖所示,31個位元組已經發送並確認。

2.    已傳送但尚未確認 已傳送但尚未得到確認的位元組。傳送方在確認之前,不認為這些資料已經被處理。下圖所示14位元組為第2類。

3.    未傳送而接收方已Ready 裝置尚未將資料發出,但接收方根據最近一次關於傳送方一次要傳送多少位元組確認自己有足夠空間。傳送方會立即嘗試傳送。如圖,第3類有6位元組。

4.    未傳送而接收方Not Ready 

由於接收方not ready,還不允許將這部分資料發出。

image003.jpg

接收方採用類似的機制來區分已接收並已確認,尚未接受但準備好接收,以及尚未接收並尚未準備好接收的資料。實際上,收發雙方各自維護一套獨立的變數,來監控傳送和接收的資料流落在哪一類。

Sequence Number設定與同步:

傳送方和接收方必須就它們將要為資料流中的位元組指定的sequence number達成一致。這一過程稱為同步,在TCP連線建立時完成。為了簡化假設第一個位元組sequence number是1,按照上圖示例,四類位元組如下:

1.     已傳送已確認位元組1至31。

2.     已傳送但尚未確認位元組32至45。

3.     未傳送而接收方已Ready位元組46至51。

4.     未傳送而接收方Not Ready位元組52至95。

傳送視窗與可用視窗:

整個過程關鍵的操作在於接收方允許傳送方一次能容納的未確認的位元組數。這稱為傳送視窗,有時也稱為視窗。該視窗決定了傳送方允許傳送的位元組數,也是2類和3類的位元組數之和。因此,最後兩類(接收方準備好而尚未傳送,接收方未準備好)的分界線在於添加了從第一個未確認位元組開始的視窗。本例中,第一個未確認位元組是32,整個視窗大小是20。

可用視窗的定義是:考慮到正在傳輸的資料量,傳送方仍被允許傳送的資料量。實際上等於第3類的大小。左邊界就是視窗中的第一個位元組(位元組32),右邊界是視窗中最後一個位元組(位元組51)。概念的詳細解釋看下圖。

image004.jpg

可用視窗位元組傳送後TCP類目與視窗大小的改變:

當上圖中第三類的6位元組立即傳送之後,這6位元組從第3類轉移到第2類。位元組變為如下:

1.     已傳送已確認位元組1至31。

2.     已傳送但尚未確認位元組32至51。

3.     未傳送而接收方已Ready位元組為0。

4.     未傳送而接收方Not Ready位元組52至95。

image005.jpg

確認處理以及視窗縮放:

過了一段時間,目標裝置向傳送方傳回確認資訊。目標裝置不會特別列出它已經確認的位元組,因為這會導致效率低下。目標裝置會發送自上一次成功接收後的最長位元組數

例如,假設已傳送未確認位元組(32至45)分為4段傳輸:32-34,35-36,37-41,42-45。第1,2,4已經到達,而3段沒有收到。接收方只會發回32-36的確認資訊。接收方會保留42-45但不會確認,因為這會表示接收方已經收到了37-41。這是很必要的,因為TCP的確認機制是累計的,只使用一個數字來確認資料。這一數字是自上一次成功接收後的最長位元組數。假設目標裝置同樣將視窗設為20位元組。

當傳送裝置接收到確認資訊,則會將一部分第2類位元組轉移到第1類,因為它們已經得到了確認。由於5個位元組已被確認,視窗大小沒有改變,允許傳送方多發5個位元組。結果,視窗向右滑動5個位元組。同時5個位元組從第二類移動到第1類,5個位元組從第4類移動至第3類,為接下來的傳輸建立了新的可用視窗。因此,在接收到確認資訊以後,看起來如下圖所示。位元組變為如下:

1.     已傳送已確認位元組1至36。

2.     已傳送但尚未確認位元組37至51。

3.     未傳送而接收方已Ready位元組為52至56。

4.     未傳送而接收方Not Ready位元組57至95。

image006.jpg

每一次確認接收以後,這一過程都會發生,從而讓視窗滑動過整個資料流以供傳輸。

處理丟失確認資訊:

但是丟失的42-45如何處理呢?在接收到第3段(37-41)之前,接收裝置不會發送確認資訊,也不會發送這一段之後位元組的確認資訊。傳送裝置可以將新的位元組新增到第3類之後,即52-56。傳送裝置之後會停止傳送,視窗停留在37-41。

TCP包括一個傳輸及重傳的計時機制。TCP會重傳丟失的片段。但有一個缺陷是:因為它不會對每一個片段分別進行確認,這可能會導致其他實際上已經接收到的片段被重傳(比如42至45)。