網路學習筆記(二):TCP可靠傳輸原理

白馬笑西風發表於2019-03-18

  TCP資料段作為IP資料包的資料部分來傳輸的,IP層提供盡最大努力服務,卻不保證資料可靠傳輸。TCP想要提供可靠傳輸,需要採取一定的措施來讓不可靠的傳輸通道提供可靠傳輸服務。比如:出現差錯時,讓傳送方重傳資料;接收方來不及處理資料時,讓傳送方降低傳輸速度。

一、資料流傳輸方式

  TCP傳輸的資料一般分為兩類:互動資料、成塊資料。互動資料一般較小,比如傳送1個位元組的互動資料,加上TCP資料段首部以及IP資料包首部,至少需要41個位元組。在廣域網,數量眾多的互動資料會增加擁塞出現的可能。而成塊資料的報文段基本上都是滿長度的。
  根據不同情況,兩種資料流採用不同的傳輸方式。

1、互動資料流傳輸

  在網際網路早期,通訊鏈路並不可靠,因此在鏈路層傳輸資料時要採用可靠的傳輸協議,其中最簡答的協議叫“停止等待協議”。在運輸層並不使用停止等待協議,只是傳輸互動資料流傳輸時採用的nagle演算法和該協議的原理很類似。

(一)、停止等待ARQ協議

  “停止等待”是指每傳送完一個分組就停止傳送,等待對方確認,在收到對方確認後再傳送下一個分組。傳送方在一定時間沒有收到確認,則會重傳分組。

停止等待協議
  如上圖所示,傳送方傳送資料分組A,接收方接收到A後,向傳送方傳送確認資料;傳送方在收到A的確認後,繼續傳送資料分組B。
  陣列分組在傳輸過程中發生錯誤時有兩種情況:

1、當接收方收到錯誤資料分組時,會直接丟棄分組。
2、如果陣列分組在傳輸的過程中丟失。

  在這兩種情況下,接收方都不會傳送任何資訊。傳送方在一定時間內沒有收到確認,就認為分組丟失,然後重傳該資料分組,這就叫超時重傳
  停止等待ARQ協議就是通過這種確認和重傳的機制,在不可靠的網路上實現可靠通訊。

(二)、nagle演算法

  在傳輸互動資料流時,一般採用nagle演算法。nagle演算法要求在一個TCP連線上最多隻能有一個未被確認的小分組,在該分組的確認到達之前不能傳送其他分組。值得注意的是:並不是在收到確認之後立刻傳送其他分組,TCP連線上允許不存在資料分組。具體的nagle演算法傳送分組的規則如下:

1、快取中的資料長度達到最大報文長度時,則允許傳送。
2、快取中的資料長度達到傳送視窗大小的一半時,則允許傳送。
3、報文段首部FIN標誌位置為1,則允許傳送。
4、報文段首部設定了TCP_NODELAY選項,則允許傳送;
5、發生了超時(一般為200ms),則立即傳送。

  TCP在未收到確認時收集這些零散的資料,當確認到達的時候,可以以一個報文段傳送出去。確認到達的越快,資料傳送的也就越快。
  nagle演算法能夠有效解決互動類的小資料過多的問題,降低網路擁塞出現的可能。但是由於不是將快取中收到的資料立刻傳送出去,因此會產生一定的時延。另外,接收方一般會延遲確認,以便將確認報文與要送的資料相結合起來,一般延遲時間為200ms。
  對於一些實時應用程式來說,nagle演算法帶來的延遲是不能夠接受的。TCP標準規定,必須實現nagle演算法,但也必須提供一種可以關閉nagle演算法的方法。上述nagle演算法規則中第四條說的TCP_NODELAY選項就是nagle演算法被關閉的標誌。

2、成塊資料流傳輸

  成塊資料往往超過最大報文長度,要進行拆分之後再傳送,互動資料碎片化的問題不會出現。成塊資料是通過基於滑動視窗協議來連續ARQ協議完成的。

(一)、滑動視窗協議

  使用基於停止等待協議的nagle演算法的缺點是通道利用率太低。如下圖所示:

網路學習筆記(二):TCP可靠傳輸原理
  如果使用流水線傳輸,那麼通道利用率會大幅提升。TCP採用滑動視窗協議來實現流水線傳輸。
網路學習筆記(二):TCP可靠傳輸原理
  滑動窗戶協議是指資料傳送方有一個傳送視窗,傳送視窗範圍內的資料允許傳送,隨著接收方傳來的確認資訊以及通知的接收視窗的大小來動態調整傳送視窗的起始位置以及大小。
網路學習筆記(二):TCP可靠傳輸原理
  如圖所示:序號1-4的資料是已經傳送過並且被確認的資料,TCP可以將這些資料清出快取;序號5-11是在視窗範圍內的資料,允許傳送;序號12-16的資料在快取中不允許傳送。
  視窗後沿是由接收方傳送的確認序號決定的,視窗前沿是由確認序號與傳送視窗大小共同決定的。而傳送視窗大小並一定等於接收方提供的接收視窗的大小,傳送方會根據網路擁塞情況來動態調整傳送視窗大小,前提是傳送方傳送視窗大小一定不大於接收方接收視窗大小。
  視窗的滑動有三種情況:

1、前沿向右移動,這種情況發生在資料傳送並被確認時。
2、後沿向右移動,允許傳送更多資料。這種情況發生在接收視窗增大或者網路擁塞情況緩解時。
3、後沿向左移動,這種情況發生在接收方希望傳送視窗縮小時,TCP標準強烈不建議出現這種情況。因為傳送方在收到縮小視窗的通知時,可能已經傳送了一些縮小部分的資料,容易造成錯誤。

  視窗前沿無法向左移動,因為TCP會將視窗之外已經收到確認的資料清除出快取。
  TCP要求接收方有累計確認功能,接收方不必立刻對收到的資料進行確認,這樣可以減少傳輸開銷。另外,在傳送確認時也可以捎帶上接收方要傳送的資料。TCP標準規定確認推遲的時間不能超過0.5秒,如果收到一個具有最大報文長度的報文段,則必須隔一個報文段就傳送一個確認。
  累積確認功能使得接收方只對按序到達的最後一個分組傳送確認,表示這個分組之前的分組已經全部到達。接收方不能夠準確的通知傳送方已經傳送到接收方的資料分組。
  例如,上圖中序號5、6、7、9、10分組到達接收方,接收方傳送的確認序號是8,即接收方沒有收到序號8的分組,希望下次收到序號8的分組。而序號9、10分組雖然已經到達的事實,傳送方並不知曉。
  這會導致一個問題:一旦發生超時重傳的情況,傳送方是否需要再次傳送已經到達的資料?如果不需要,又該如何獲知具體哪些資料已經到達?
  滑動視窗協議自動重傳請求技術結合形成連續ARQ協議連續ARQ協議根據超時重發資料方式的不同分為後退N幀ARQ協議選擇重發ARQ協議

(二)、後退N幀ARQ協議

  在發生超時重傳時,後退N幀ARQ協議不考慮確認序號之後的分組是否已經傳送到接收方,直接從確認序號開始重傳之後的資料。

網路學習筆記(二):TCP可靠傳輸原理
  如上圖所示:序號5、6、7、9、10分組到達接收方,確認序號為8。假如視窗大小不變,則視窗向右滑動,序號8-14在傳送視窗中。超時重傳時不考慮序號9、10是否到達接收方,重傳序號8之後的全部在傳送視窗的資料。

(三)、選擇重傳ARQ協議

  選擇重傳ARQ協議是指在接收方收到未按序排列的資料流時,通知傳送方重傳缺失的資料,而不是重傳全部資料。TCP資料段首部中新增選擇確認選項SACK可以實現該目的。

網路學習筆記(二):TCP可靠傳輸原理
  如圖所示,假設上述分組都在傳送視窗中,收到三個不連續的分組。三個分組的邊界分別為:[4000,5001]、[6000,7001]、[8000,9001]。在建立TCP連線時,連線雙方先商定好,在首部選項中加入“允許SACK”的選項。在之後的TCP報文段中增加SACk選項,以便接收方向傳送方報告不連續的位元組塊的邊界。
  因為序號是32位,因此指明一個邊界需要4個位元組,說明一個位元組塊的邊界需要8個位元組。另外需要一個位元組指明是SACK選項,一個位元組指明這個選項的大小。TCP報文段首部選項最大為40個位元組,因此最多指明4個位元組塊的邊界資訊。
  TCP標準並未指明傳送方應該如何響應SACK,因此大多數實現還是重傳所有未被確認的資料分組。

二、超時重傳時間

  對於每一個連線,TCP管理這4個不同的定時器:

1、重傳定時器:決定何時重傳未被確認的資料分組。
2、堅持定時器:使視窗大小資訊保持不斷流動。
3、保活定時器:檢測空閒連線的另一端是否崩潰或重啟。
4、2MSL定時器:測量一個連線處於TIME_WAIT狀態的時間。

  在超時重傳的情況下,如果將超時重傳的時間設定的太短,會出現很多不必要的重傳,增大網路負荷;如果設定的時間太長,則使網路的空閒時間增大,降低傳輸效率。TCP採用一種自適應的演算法來動態計算超時重傳的時間。

1、報文段往返時間

  一個報文段發出的時間與收到確認的時間只差就是報文段的往返時間RTT平滑的往返時間RTT_S是RTT的加權平均值。第一次測量時,RTT_S等於RTT的值,之後測量到新的RTT值時按以下公式計算:

新的RTT_S = (1 - α)×(舊的RTT_S)+ α ×(新的RTT樣本)

  TCP標準推薦α的值為0.125。
  RTT偏差的加權平均值RTT_D,與RTT_S和新的RTT樣本之差有關。第一次測量時,RTT_D的值取RTT的一半,之後的測量中採用如下公式:

新的RTT_D = (1 - β)×(舊的RTT_D)+ β × |RTT_S - 新的RTT樣本|

  TCP標準推薦β的值為0.25。
  超時計時器設定的超時重傳時間RTO由如下公式求得:

RTO = RTT_S + 4 × RTT_D

2、Karn演算法

  在實際測量報文段往返時間RTT時會遇到一些問題,如下圖所示:

網路學習筆記(二):TCP可靠傳輸原理
  傳送報文段後,在一定時間內沒有收到確認。重傳該報文段,之後收到確認報文。那麼怎麼確定確認報文是對哪個報文的確認?因為重傳的報文和原報文完全相同,收到的確認報文也相同。那麼報文段往返時間RTT是A還是B呢?
  在上述情況下,Karn提出一個演算法:在計算加權平均RTT_S時,只要報文段重傳了,就不採用其往返時間樣本。這樣的到的加權平均RTT_S和RTO就比較準確。
  Karn演算法也存在問題:當報文段的時延突然增大很多時,在原重傳時間內不會收到確認報文,於是重傳該報文段。根據Karn演算法,重傳的報文段往返時間不會被採用,因此超時重傳時間就無法更新。
  因此要對Karn演算法進行修正:報文重傳時,就把超時重傳時間RTO增大一些。典型的做法是重傳時間變成原來的兩倍。當不再發生重傳時,再根據計算公式算出超時重傳時間。

三、流量控制

  通過TCP連線傳送資料,如果傳送方傳送資料很慢,容易造成資源浪費;如果傳送方傳送資料過快,接收方來不及接收會造成資料丟失。流量控制就是指在接收方能夠接收的範圍內,合理而又快速的傳送資料。

1、基於滑動視窗的流量控制

  利用滑動視窗機制可以實現對傳送方的流量控制。在TCP連線建立時,接收方會在確認報文段中給出自己接收視窗的大小。在每次傳送確認報文時能夠根據情況動態調整接收視窗的大小,並將告知傳送方。如下圖所示:

網路學習筆記(二):TCP可靠傳輸原理
  傳送方傳送序號從1開始的100位元組的資料,接收方在確認報文中宣告自身的接收視窗大小為300位元組。之後傳送方傳送300位元組資料,接收方在確認報文中宣告自身接收視窗大小調整為50位元組。傳送方再傳送50位元組資料之後,收到接收方傳來的確認報文,在該報文中宣告接收視窗為0。
  在接收方接收視窗為0時,傳送方不再傳送資料,直到接收方傳送確認報文表明視窗大小發生改變。可是這個確認報文不一定能夠被髮送方接收到,如果一旦該確認報文丟失,雙方都將處於等待中,形成死鎖。為防止這種情況出現,TCP規定在收到對方接受視窗為0時,啟動一個堅持定時器週期性的傳送探測報文,以確定對方接收視窗為0的狀態是否改變。
  另外,TCP標準規定:接收方接收視窗為0時,不再接收正常資料,但是可以接收零視窗探測報文段確認報文段攜帶緊急資料的報文段

2、糊塗視窗綜合症

  糊塗視窗綜合症是指僅僅有少量資料通過連線進行交換,而不是滿長度的報文段。這樣會導致網路傳輸的效率很低。
  如果接收快取已經存滿,此時接收方的應用程式每次只從接收快取中讀取少量資料,則接收方的接收視窗會一直保持在一個較低的值,導致傳送方每次只能傳送少量資料,會導致糊塗視窗綜合症
  如果傳送方應用程式每次向傳送快取中寫入少量資料,TCP選擇每次收到資料之後立即傳送,也會導致糊塗視窗綜合症
  避免糊塗視窗綜合症可以從兩端採取解決措施:

1、接收方不通告小視窗。通常的演算法是接收方不通告一個比當前視窗大的視窗(可以為0),除非視窗可以增加一個報文段大小(也就是將要接收的MSS)或者可以增加接收方快取空間 的一半,不論實際有多少。
2、 傳送方在存在滿長度的報文段或者接收方通告視窗大小一半報文時才傳送。

四、MSS

  最大報文段長度MSS是指每一個TCP報文段中資料欄位的最大長度。資料欄位長度加上首部長度就等於TCP報文段的長度。
  MSS是在建立TCP連線時通訊雙方協商確定的。第一次握手時,傳送方可以在首部中增加MSS選項,如果沒有MSS選項,則MSS預設為1460位元組。第二次握手時,接收方也可以在選項中增加MSS選項,最終MSS的值取連線雙方宣告的MSS中最小值。
  如果資料鏈路層使用乙太網的話,最大傳輸單元MTU為1500位元組,IP資料包首部最少為20位元組,TCP資料段首部至少為20位元組,那麼MSS最大為1460位元組。如果資料鏈路層使用網際網路,那麼MTU=576位元組,MSS最大為536位元組。
  在網路層,如果傳輸的資料大於MTU,則會在傳送端進行資料分片,然後再接收端的網路層進行組合。如果其中任何一個分片產生錯誤,都會導致整個TCP報文段重傳。因此TCP會對資料進行分段,分段之後的資料往下交付不會超過MTU,可以避免網路層對資料進行分片。在傳輸層,UDP不像TCP那樣進行資料分段,UDP會將應用程式交付下來的整個資料封成一個資料包,如果資料包大小超過MTU,則由網路層進行分片。

五、擁塞控制

  擁塞控制是指防止過多的資料注入網路中,這樣可以使網路中路由器或者鏈路不致過載。現在通訊線路的傳輸質量一般都很好,因傳輸出現差錯丟棄分組的概率很小。因此,判斷網路擁塞的依據就是出現了超時
  TCP進行擁塞控制常用的演算法有四種:慢啟動擁塞避免快重傳快恢復

1、慢啟動

  TCP為傳送方維持一個擁塞視窗,記為cwnd。擁塞視窗是傳送方使用的流量控制,接收方宣告的接收視窗是接收方使用的流量控制。傳送方的傳送視窗大小等於這兩個視窗中的最小值。
  擁塞視窗的值跟SMSS有關,SMSS為傳送的最大報文段長度。舊的規定是擁塞視窗的初始值為1至2個SMSS,RFC 5681規定擁塞視窗的初始值不超過2至4個SMSS。具體規定如下:

1、若SMSS>2190位元組,則cwnd=2×SMSS位元組,且不得超過2個報文段。
2、若2190≥SMSS>1095位元組,則cwnd=3×SMSS位元組,且不得超過3個報文段。
3、若SMSS≥1095位元組,則cwnd=4×SMSS位元組,且不得超過4個報文段。

  慢啟動演算法規定:擁塞視窗初始化後,每收到一個對新報文的確認,擁塞視窗就加一個SMSS的大小。擁塞視窗以位元組為單位,但是慢啟動以SMSS大小為單位增加。按照慢啟動演算法,經過一輪傳輸,擁塞視窗就增大一倍,這是一種指數增長的關係。

2、擁塞避免

  慢啟動演算法除了維持擁塞視窗cwnd變數之外,還維持另一個變數慢啟動門限ssthresh。當cwnd以指數增長的形式增長到大於或等於ssthresh時,就不再採用慢啟動演算法,而是採用擁塞避免演算法來進行擁塞控制。
  擁塞避免演算法規定:每次收到一個確認時將cwnd增加1/cwnd個SMSS。即不再是像慢啟動演算法那樣經過一輪傳輸cwnd翻倍了,而是經過一輪傳輸增加一個SMSS。這是一種加性增長的關係。
  當擁塞發生時(超時或收到重複確認),cwnd被設定為1個SMSS。ssthresh被設定為當前視窗大小的一半,但最少為 2個報文段。
  例如:假設TCP的ssthresh的初始值為 8 SMSS。當擁塞視窗上升到 12 SMSS時網路發生了超時,TCP使用慢開始和擁塞避免。擁塞視窗大小如下圖所示:

網路學習筆記(二):TCP可靠傳輸原理

3、快重傳

  如果個別報文段在網路中丟失,網路並沒有發生擁塞,這種情況下傳送方收不到確認報文,在超時之後會重傳該報文。傳送方誤以為網路發生擁塞,錯誤的啟動慢開始演算法,降低了傳輸效率。
  採用快重傳演算法可以讓傳送方儘早知道個別報文段的丟失。快重傳演算法要求接收方不要延時傳送確認,即使收到失序的報文段也要立刻傳送對已收到報文的重複確認。如下圖所示:

網路學習筆記(二):TCP可靠傳輸原理
  接收方收到M1之後傳送對M1的確認報文,M2報文丟失,之後接收方收到M3、M4、M5時每次都傳送對M1報文的重複確認。快重傳演算法規定當收到三次重複確認後,傳送方就認為M2報文段丟失,立即重傳M2報文段,而不用等待超時時再重傳,這樣可以避免傳送方誤認為網路發生擁塞。使用快重傳可以使整個網路的吞吐量提高約20%。

4、快恢復

  在快重傳演算法執行後,傳送方知道只是丟失個別報文,而不是網路發生擁塞。之後並不會執行慢啟動演算法,而是執行快恢復演算法:調整門限值ssthresh = cwnd/2,同時設定cwnd = ssthresh + 3 SMSS。這種設定門限值為當前擁塞視窗的一般,同時根據門限值調整擁塞視窗的形式稱為乘法減小
  為什麼要設定擁塞視窗的值為門限值加3個報文段,而不是直接等於門限值?這是因為傳送方收到三個確認報文,就認為有三個分組已經離開網路到達接收方的快取,這三個確認報文不再佔用網路資源,可以適當增大擁塞視窗的大小。

六、總結

  TCP資料流傳輸方式分為:互動資料流、成塊資料流。互動資料流採用nagle演算法來控制流量,成塊資料流通過基於滑動視窗協議連續ARQ協議完成的。連續ARQ協議根據超時重傳時是重傳全部資料還是選擇性的重傳而分為:後退N幀ARQ協議選擇重傳ARQ協議
  超時重傳的時間是動態確定的,根據報文段往返時間經過改進後的Karn演算法來計算的。
  流量控制就是指在接收方能夠接收的範圍內,合理而又快速的傳送資料。傳送方與接收方都要採取措施來防止糊塗視窗綜合症情況的發生。
  最大報文段長度MSS是在建立連線時由雙方協商確定的,TCP資料包的MSS受限於網路層的最大傳輸單元MTU。TCP會將應用程式交付的資料進行分段,每個報文段加上TCP報文段首部以及IP資料包首部不會超過MTU,這樣網路層就不會對TCP資料段進行分片。UDP會將應用程式交付的資料打包成一個UDP資料包,分片任務由網路層來完成。
  TCP進行擁塞控制常用的演算法有四種:慢啟動擁塞避免快重傳快恢復。這四種演算法一般都不是孤立使用的,慢啟動擁塞避免之間會根據擁塞視窗是否達到ssthresh以及是否發生重傳來切換;快重傳演算法之後緊跟著使用快恢復演算法。
如需轉載,煩請註明出處:www.cnblogs.com/lidengfeng/…

相關文章