天天看點

TCP的精髓

TCP協定作為一個可靠的面向流的傳輸協定,其可靠性和流量控制由滑動視窗協定保證,而擁塞控制則由控制視窗結合一系列的控制算法實作。

一、滑動視窗協定

關于這部分自己不曉得怎麼叙述才好,因為了解的部分更多,下面就用自己的了解來介紹下TCP的精髓:滑動視窗協定。
 所謂滑動視窗協定,自己了解有兩點:1. “視窗”對應的是一段可以被發送者發送的位元組序列,其連續的範圍稱之為“視窗”;2. “滑動”則是指這段“允許發送的範圍”是可以随着發送的過程而變化的,方式就是按順序“滑動”。在引入一個例子來說這個協定之前,我覺得很有必要先了解以下前提:      
  1. TCP協定的兩端分别為發送者A和接收者B,由于是全雙工協定,是以A和B應該分别維護着一個獨立的發送緩沖區和接收緩沖區,由于對等性(A發B收和B發A收),我們以A發送B接收的情況作為例子;
  2. 發送視窗是發送緩存中的一部分,是可以被TCP協定發送的那部分,其實應用層需要發送的所有資料都被放進了發送者的發送緩沖區;
  3. 發送視窗中相關的有四個概念:
  • 已發送并收到确認的資料(不再發送視窗和發送緩沖區之内)
  • 已發送但未收到确認的資料(位于發送視窗之中)
  • 允許發送但尚未發送的資料
  • 發送視窗外發送緩沖區内暫時不允許發送的資料;
  1. 每次成功發送資料之後,發送視窗就會在發送緩沖區中按順序移動,将新的資料包含到視窗中準備發送;
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位元組的試探封包;

    -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. 執行擁塞避免算法(高起點,線性增長);

回到頂部

四、可靠傳輸的停止等待協定和連續ARQ協定

網絡傳輸的理想傳輸狀态就是:

1、傳輸信道不産生差錯。

2、不管發送方以多塊的速度發送資料,接收方都能來得及接受以及處理這些資料。      

當然,這種隻是理想狀态,在實際運用中,幾乎是不可能的。是以,我們需要采取一些可靠的傳輸協定。

1、當出現差錯時,讓發送發重傳該差錯資料。

2、接受方來不及處理資料時,及時告知發送方适當的降低發送速度。      

那麼,要做到上述第一點,就需要采用:停止等待協定

  1. 停止等待協定

    所謂停止等待協定就是沒發送完一組資料後,等待對方确認并且收到确認後,再發送下一組資料。

    我将它簡單的了解為以下過程:發送資料,收到資料,發送确認,收到确認。

    那麼這樣,就分為了以下4種情況。(無差錯、出現差錯、确認丢失、确認遲到)

    1、無差錯

所謂無差錯,就是資料能夠正常發送,正常接收,正常确認,正常收到确認的一個過程。也是最理想,最好的一種狀态。      

2、出現差錯

所謂出現差錯,就是資料在發送的過程中部分或全部丢失(如上圖左)。

 A發送M1并出現差錯,B在收到M1時(全部丢失,不會收到)檢測出了差錯,就丢棄M1,其他什麼也不做(不會通知A資料出現了差錯,因為有可能全部丢失,B并不知道)。在這兩種情況下,B都不會發送任何的資訊。那麼,怎麼辦?

 A隻要超過一段時間仍然沒有收到确認,就認為剛才所發送的資料丢失,然後重傳前面發送的資料。這就叫做逾時重傳。目前需要一個計時器來完成。

 是以,有如下三點要求:

 1>、A在發送完一組資料後,必須暫時保留自己已發送的資料的副本(供逾時重傳使用)。隻有收到确認後,才會删除該副本。

 2>、每一組資料和确認資料都必須編号(TCP頭部有該字段)。這樣才能明确是哪一個發送出去的資料收到了确認,哪一個沒有收到。

 3>、逾時計時器設定的時間應該要長于資料平均往返時間。      

3、确認丢失

所謂确認丢失,其實就是确認消息在傳輸過程丢失。那麼,該如何處理?

 當A發送M1消息,B收到後,B向A發送了一個M1确認消息,但卻在傳輸過程中丢失。而A并不知道,在逾時計時過後,A重傳M1消息,B再次收到該消息後采取以下兩點措施:

 1>、丢棄這個重複的M1消息,不向上層傳遞。

 2>、向A發送确認消息。(不會認為已經發送過了,就不再發送。A能重傳,就證明B的确認消息丢失)。      

4、确認遲到

所謂确認遲到,就是B發送的确認消息沒有丢失,但是卻遲到(過了很長一段時間才到)。那麼該如何處理?

 A發送M1消息,B收到并發送确認。在逾時時間内沒有收到确認消息,A重傳M1消息,B仍然收到并繼續發送确認消息(B收到了2份M1)。此時A收到了B第二次發送的确認消息。接着發送其他資料。過了一會,A收到了B第一次發送的對M1的确認消息(A也收到了2份确認消息)。處理如下:

 1>、A收到重複的确認後,直接丢棄。

 2>、B收到重複的M1後,也直接丢棄重複的M1。      

至此,就是停止等待協定中所出現的所有的可能情況。也一一解決。像這種可靠的傳輸協定通常稱為自動重傳請求ARQ(Automatic Repeat reQuest)。意思就是,重傳的請求是自動進行的,不需要接受方請求發送某一個丢失或出錯的消息。

但是,很顯然。我們發現,其信道的使用率很低。

那該怎麼辦?

  1. 連續ARQ協定  

    先看一張信道使用率圖:

這兩張圖的差異很明顯。使用連續的ARQ協定可以大大的提高信道使用率。

吧後者這張圖的工作模式又叫做流水線傳輸。

其原理如下:



 其實作的基礎是建立在滑動視窗之上。而滑動視窗乃是TCP的精髓所在(下一篇詳解)。

 連續ARQ規定,發送方每收到一個确認就将滑動視窗向前(時間增大方向)滑動一格。如上圖表示收到一個确認。

 接受方采用累積确認的方式:接收方不必每收到一個消息,就發送一個确認。而是在收到幾條消息後,對按序到達的最後一條消息發送确認。表示,這個消息之前的所有消息全部收到。



當然,這兩個方式都有自己的優缺點:

1、自動重傳請求ARQ協定

 優點:簡單

 缺點:信道使用率低

2、連續的ARQ協定

優點:信道使用率高,容易實作,即使确認丢失,也不必重傳。

缺點:不能向發送方反映出接收方已經正确收到的所有分組的資訊。

比如:發送方發送了5條消息,中間第三條丢失(3号),這時接收方隻能對前兩個發送确認。發送方無法知道後三個分組的下落,而隻好把後三個全部重傳一次。這也叫