TCP的流量控制

下面簡單介紹了TCP的流量控制。算法

流量控制是發送方和接收方合做完成的端到端的流量控制,用於防止發送方發送數據包的速率超過了接收方的接收速率,形成了接收方溢出。網絡

流量控制早於擁塞控制出現,是實現擁塞控制的基礎,所以在深刻學習擁塞控制以前,有必要回顧流量控制。性能

 

1.1   Acknowledgement機制

TCP基於ACK實現可靠傳輸。sender每發送一個packet,都會等待receiver的響應,而receiver收到packet以後,會當即反饋一個ACK,ACK代表receiver成功收到了該packet[5]學習

ACK機制得以穩定運行的前提之一是全部的數據都是按序編號的,所以packet和其ACK便有了對應的依據。實際上,TCP不但將全部數據依次編號,並且精確到字節。在sender發送的每一個packet的頭部信息中,都寫明瞭其序號(sequence number),同時,receiver在每一個ACK中,都寫明瞭所指望的下一個packet的序號,sender再基於該序號發送接下來的packet。ACK機制使得TCP得以自我運轉,而不依賴外部因素,所以在一些文獻中,Acknowledgement機制又稱爲Self-Clocking機制。spa

基於Acknowledgement機制,產生了「數據包守恆準則」[6]。根據該準則,若是一個網絡上穩定地傳輸着滿額的數據包,就認爲它是平衡的。一個平衡的網絡上,只有在有數據包離開時,纔會有新的數據包加入。所以,平衡的網絡能夠避免擁塞的發生。ip

從sender發送packet起,到收到相應的ACK止,這個時間間隔稱爲一個RTT(roung trip time),該時間是在TCP運行的過程當中,經過實時統計和估算獲得的,而且是動態改變的[1]io

1.2   Cumulative Acknowledgement

在非SACK[17]的TCP中,receiver採起累積確認的模式[2]。在發送ACK時,老是回覆這樣一個序號,該序號以前的全部packet都已被receiver接收,與它相鄰的下一個packet沒有被receiver接收。即累積回覆從左到右最大的一塊連續區域。累積確認在所到達的packet填補了receiver緩衝區的空洞時,會被體現出來。ast

1.3   Sliding Window機制

sender和receiver都維持各自的window,分別稱爲發送窗口和接收窗口。發送窗口(send window)規定了可發送的範圍,sender只能按序地發送該窗口內的packet。接收窗口(receive window)則至關於receiver的可用緩衝區(不必定相等,但有直接關係),用於接收來自sender的packet。另外,發送窗口又分爲先後兩部分:class

[SND.UNA, SND.NXT)之間的部分,此窗口內的packet已經被髮送出去,但還沒有收到ACK,RFC1122稱這些packet爲outstanding的,即還在網絡中傳輸的。基礎

[SND.NXT, SND.UNA+SND.WND]之間的部分,稱爲可用窗口(usable window),此窗口內的packet還沒有被髮送出去。

其中,SND.UNA表示還沒有收到ACK的packet中最靠左的一個,也是發送窗口的起點。

SND.NXT表示即將發送的下一個packet的序號。

SND.WND表示發送窗口的大小。

能夠看出,隨着sender不斷地接受ACK,SND.UNA的值會遞增,發送窗口就會不斷地向右滑動,這就是滑動窗口機制。

窗口的概念是Flow Control的基礎。Flow Control協調雙方的速率,實際上就是協調雙方窗口大小。實現窗口協調的前提是,至少有一方可以獲知對方窗口的大小。爲此,在每一個ACK中,都會寫明receiver的接收窗口的大小(稱爲offered window),使得sender能夠依此調節發送窗口的大小。sender將接收窗口大小減去還沒有收到ACK的數據的大小,做爲可用窗口的大小,從而控制發送速率[5]

對於receiver來講,

LastByteRcvd – LastByteRead <= RcvBuffer

rwnd = RcvBuffer – [LastByteRcvd – LastByteRead]

對於sender來講,

LastByteSent – LastByteAcked <= rwnd

SND.UNA=LastByteAcked-1

SND.NXT=LastByteSent-1

SND.WND=rwnd

1.4   Silly Window Syndrome

所謂Silly Window Syndrome[5],能夠用下面一個例子解釋。

假設receiver最初告訴sender,接收窗口的初始值爲有1000字節,那麼發送窗口/可用窗口的初始值也爲1000字節。再假設每一個packet的大小被設置爲200字節,那麼第一次sender會發送5個packet。當receiver接收到第一個packet後,有兩種處理方式:(1)能夠將其當即提交給應用層,從而從新騰出緩衝區,此時ACK中的offered window仍然是1000字節。(2)也能夠不處理,等到必定時刻,再提交給應用層,此時ACK中的offered window就是1000-200=800字節。對於第二種方式,sender在收到ACK後,計算可用窗口的大小,結果爲800-800=0,即sender不能繼續發送數據,直到receiver騰出更多緩衝區爲止。

咱們下面只考慮第一種方式,此時sender計算到的可用窗口的大小爲1000-800=200,所以sender能夠發送一個新的200字節的packet。實際上能夠看出,sender發送數據的大小就是receiver接收數據的大小。接下來考慮一種異常,某個時刻,可用窗口的大小爲200字節,可是應用層要發送的數據只有50字節而且設置了PUSH,此時sender只能將50字節的數據做爲一個packet發送出去,一個RTT後,sender收到對應的ACK,從新計算可用窗口的大小爲1000-950=50字節,所以sender仍然只能發送50字節的packet。能夠預見,50字節的窗口會一直存在,網絡中會持續出現零碎的packet,所以TCP性能會下降。

在RFC813中提出瞭解決方法,主要思想是當sender遇到小窗口時,推遲新packet的發送,以等待receiver騰出更大的接收窗口再發送。這種思想分別運用到sender和receiver之上,造成了兩種算法。(1)在sender端,會計算可用窗口相對接收窗口的比例,當其小於一個閾值時,就推遲新packet的發送。(2)在receiver端,若是發現offered window很小,那麼會進一步將ACK中的offered window的值減少,使得sender計算獲得的可用窗口太小而沒法發送新的packet。等騰出更大接收窗口時,再一次性通知sender,使其得以繼續發送packet。

相關文章
相關標籤/搜索