TCP滑動視窗機制 流量控制 擁塞控制
轉自http://blog.chinaunix.net/uid-26275986-id-4109679.html
TCP協議作為一個可靠的面向流的傳輸協議,其可靠性和流量控制由滑動視窗協議保證,而擁塞控制則由控制視窗結合一系列的控制演算法實現。
一、滑動視窗協議
關於這部分自己不曉得怎麼敘述才好,因為理解的部分更多,下面就用自己的理解來介紹下TCP的精髓:滑動視窗協議。
所謂滑動視窗協議,自己理解有兩點:1. “視窗”對應的是一段可以被髮送者傳送的位元組序列,其連續的範圍稱之為“視窗”;2. “滑動”則是指這段“允許傳送的範圍”是可以隨著傳送的過程而變化的,方式就是按順序“滑動”。在引入一個例子來說這個協議之前,我覺得很有必要先了解以下前提:
-1. TCP協議的兩端分別為傳送者A和接收者B,由於是全雙工協議,因此A和B應該分別維護著一個獨立的傳送緩衝區和接收緩衝區,由於對等性(A發B收和B發A收),我們以A傳送B接收的情況作為例子;
-2. 傳送視窗是傳送快取中的一部分,是可以被TCP協議傳送的那部分,其實應用層需要傳送的所有資料都被放進了傳送者的傳送緩衝區;
-3. 傳送視窗中相關的有四個概念:已傳送並收到確認的資料(不再發送視窗和傳送緩衝區之內)、已傳送但未收到確認的資料(位於傳送視窗之中)、允許傳送但尚未傳送的資料以及傳送視窗外發送緩衝區內暫時不允許傳送的資料;
-4. 每次成功傳送資料之後,傳送視窗就會在傳送緩衝區中按順序移動,將新的資料包含到視窗中準備傳送;
TCP建立連線的初始,B會告訴A自己的接收視窗大小,比如為‘20’:
位元組31-50為傳送視窗
A傳送11個位元組後,傳送視窗位置不變,B接收到了亂序的資料分組:
只有當A成功傳送了資料,即傳送的資料得到了B的確認之後,才會移動滑動視窗離開已傳送的資料;同時B則確認連續的資料分組,對於亂序的分組則先接收下來,避免網路重複傳遞:
二、流量控制
流量控制方面主要有兩個要點需要掌握。一是TCP利用滑動視窗實現流量控制的機制;二是如何考慮流量控制中的傳輸效率。
1. 流量控制
所謂流量控制,主要是接收方傳遞資訊給傳送方,使其不要傳送資料太快,是一種端到端的控制。主要的方式就是返回的ACK中會包含自己的接收視窗的大小,並且利用大小來控制傳送方的資料傳送:
這裡面涉及到一種情況,如果B已經告訴A自己的緩衝區已滿,於是A停止傳送資料;等待一段時間後,B的緩衝區出現了富餘,於是給A傳送報文告訴A我的rwnd大小為400,但是這個報文不幸丟失了,於是就出現A等待B的通知||B等待A傳送資料的死鎖狀態。為了處理這種問題,TCP引入了持續計時器(Persistence timer),當A收到對方的零視窗通知時,就啟用該計時器,時間到則傳送一個1位元組的探測報文,對方會在此時迴應自身的接收視窗大小,如果結果仍未0,則重設持續計時器,繼續等待。
2. 傳遞效率
一個顯而易見的問題是:單個傳送位元組單個確認,和視窗有一個空餘即通知傳送方傳送一個位元組,無疑增加了網路中的許多不必要的報文(請想想為了一個位元組資料而新增的40位元組頭部吧!),所以我們的原則是儘可能一次多傳送幾個位元組,或者視窗空餘較多的時候通知傳送方一次傳送多個位元組。對於前者我們廣泛使用Nagle演算法,即:
*1. 若傳送應用程序要把傳送的資料逐個位元組地送到TCP的傳送快取,則傳送方就把第一個資料位元組先發送出去,把後面的位元組先快取起來;
*2. 當傳送方收到第一個位元組的確認後(也得到了網路情況和對方的接收視窗大小),再把緩衝區的剩餘位元組組成合適大小的報文傳送出去;
*3. 當到達的資料已達到傳送視窗大小的一半或以達到報文段的最大長度時,就立即傳送一個報文段;
對於後者我們往往的做法是讓接收方等待一段時間,或者接收方獲得足夠的空間容納一個報文段或者等到接受快取有一半空閒的時候,再通知傳送方傳送資料。
三、擁塞控制
網路中的鏈路容量和交換結點中的快取和處理機都有著工作的極限,當網路的需求超過它們的工作極限時,就出現了擁塞。擁塞控制就是防止過多的資料注入到網路中,這樣可以使網路中的路由器或鏈路不致過載。常用的方法就是:
1. 慢開始、擁塞控制
2. 快重傳、快恢復
一切的基礎還是慢開始,這種方法的思路是這樣的:
-1. 傳送方維持一個叫做“擁塞視窗”的變數,該變數和接收埠共同決定了傳送者的傳送視窗;
-2. 當主機開始傳送資料時,避免一下子將大量位元組注入到網路,造成或者增加擁塞,選擇傳送一個1位元組的試探報文;
-3. 當收到第一個位元組的資料的確認後,就傳送2個位元組的報文;
-4. 若再次收到2個位元組的確認,則傳送4個位元組,依次遞增2的指數級;
-5. 最後會達到一個提前預設的“慢開始門限”,比如24,即一次傳送了24個分組,此時遵循下面的條件判定:
*1. cwnd < ssthresh, 繼續使用慢開始演算法;
*2. cwnd > ssthresh,停止使用慢開始演算法,改用擁塞避免演算法;
*3. cwnd = ssthresh,既可以使用慢開始演算法,也可以使用擁塞避免演算法;
-6. 所謂擁塞避免演算法就是:每經過一個往返時間RTT就把傳送方的擁塞視窗+1,即讓擁塞視窗緩慢地增大,按照線性規律增長;
-7. 當出現網路擁塞,比如丟包時,將慢開始門限設為原先的一半,然後將cwnd設為1,執行慢開始演算法(較低的起點,指數級增長);
上述方法的目的是在擁塞發生時循序減少主機發送到網路中的分組數,使得發生擁塞的路由器有足夠的時間把佇列中積壓的分組處理完畢。慢開始和擁塞控制演算法常常作為一個整體使用,而快重傳和快恢復則是為了減少因為擁塞導致的資料包丟失帶來的重傳時間,從而避免傳遞無用的資料到網路。快重傳的機制是:
-1. 接收方建立這樣的機制,如果一個包丟失,則對後續的包繼續傳送針對該包的重傳請求;
-2. 一旦傳送方接收到三個一樣的確認,就知道該包之後出現了錯誤,立刻重傳該包;
-3. 此時傳送方開始執行“快恢復”演算法:
*1. 慢開始門限減半;
*2. cwnd設為慢開始門限減半後的數值;
*3. 執行擁塞避免演算法(高起點,線性增長);