這里只是簡單梳理TCP各版本的控制原理,對於基本的變量定義,可以參考以下鏈接:
TCP基本擁塞控制http://blog.csdn.net/sicofield/article/details/9708383
TCP中RTO計算http://www.tuicool.com/articles/Yn6vEr
TCP擁塞控制名詞解釋:
1.awnd(advised window) 通告窗口,由接收端tcp發送給發送端tcp,告訴發送端自己能用於接收新的數據包的當前可用空間。
2.cwnd(congestion window)擁塞窗口,人為引入的變量,用於擁塞控制。因為如果單獨使用awnd,每次都按接收端最大窗口發送易引發網絡的瞬時擁塞瞬時進入擁塞避免劇烈降低網絡利用率。
3.ssthresh(slow start thresh)慢啟動閾值,用於確定使用慢啟動算法還是擁塞避免算法。當前窗口小於ssthresh的時候,使用慢啟動算法按指數增加窗口;當前窗口等於ssthresh時,使用慢啟動或擁塞避免算法增長發送窗口都可以;當前發送窗口大於ssthresh時,使用擁塞避免算法,按線性增加發送窗口。
4.發送窗口W = min(cwnd, awnd)
5.duplicate ACK重復ACK,TCP接收端在接受到錯序/失序數據包時應該立即向發送端返回重復ACK。如接收端已經順序收到1000號前的包,返回發送端1001,然后接收端接着收到了1002號包,而不是期望的1001號包,則其立即返回給發送端1001的ACK包,這個ACK相對於第一次的1001ACK就是重復ACK包。
原始版TCP協議--TCP-Tahoe:
1.慢啟動
初始值cwnd=1(linux3.0之后是10),ssthresh初始值可以被設置為任意大(可以設置為awnd或更大,這樣總是使TCP從慢啟動算法開始,而不是擁塞避免算法),如linux 3.2.12是int最大值0x7fffffff.
該階段,每個rtt周期發送窗口W加倍。時間曲線圖中表現為指數曲線。
2.擁塞避免
如果出現丟包,由於TCP無法確認丟包類型,所以就認為發生了網絡擁塞,重傳包並進入擁塞避免算法。操作是:
ssthresh = max(flight size/2, 2*SMSS),flight size為當前發送窗口中已經發送但還沒有收到ACK的包個數,即flight size<=W,SMSS為發送端最大分組大小。
cwnd=1(或其他初始值,如10),然后就可以重新從慢啟動算法增加發送窗口。
3.丟包,重現慢啟動
在上一步的基礎上,根據新的初值,回到第1步重新執行慢啟動。
如下圖:
說明:
1.tcp啟動時,cwnd=1,ssthresh=16,時間軸0-4是慢啟動算法階段。然后發送窗口增加到ssthresh時,進入擁塞避免階段,時間軸4-12.
2.發送丟包時,cwnd重新置為1,ssthresh設置為當前擁塞窗口(24)的一半,即12.時間軸上12-13.
3.上一步設置完新的cwnd和ssthresh后,重新進入第1步進行執行慢啟動算法。
后期Tahoe版本也引入了快重傳算法(原始檢測到丟包需要等到rto超時才能重傳,快重傳就是連續收到3個ack就立即重傳)。
快恢復版本TCP--TCP-Reno(增加快重傳/快恢復算法):
Tahoe版本檢測丟包只能通過RTO超時依然收不到ACK時才能開始重傳,Reno版的修改是,引入快重傳機制:當收到對方連續3次重復ACK時,不必再等待RTO超時,認為網絡已經發生擁塞丟包,立即重傳數據包。同時,因為RTO時間內連續收到3次ACK,認定網絡狀況依然良好,丟包可能是網絡發生了瞬時擁塞。所以不必對發送窗口進行過度調整。
快重傳機制(Fast Retransmit):
當收到3次連續的重復ACK時,立即重傳數據包,不必等待RTO超時。
注意:快重傳不必一定跟快恢復算法同時使用。Tahhoe版本中也可以使用快重傳,但cwnd依然調整為1,而不是快恢復算法的cwnd/2.
窗口示例:
快重傳/快恢復算法(Fast Recovery):
1.收到3次重復ACK,設置ssthresh=cwnd/2。
2.重傳丟失的包,設置cwnd=ssthresh+3。3是根據網絡“數據包守恆”定律,即根據ACK機制,收到3個重復ACK,說明有3個數據包已經離開了網絡,所以cwnd+3。
3.每收到一個額外的重復ACK(包5),cwnd=cwnd+1。只是為了反應出一個包已經離開網絡的事實。
4.傳輸包
5.如果收到新數據包的ACK(包7或包9),cwnd=ssthresh,稱為“縮小窗口”,退出快恢復階段,進入擁塞避免階段。
對應下圖時間軸12-13.
總結:
TCP擁塞控制算法 RFC文檔鏈接http://www.faqs.org/rfcs/rfc2581.html
新版本TCP--TCP NewReno(相對Reno少量但卻重要的修改是對partial acknowledgment部分確認的處理):
Reno版本不足:
當發送窗口只有一個包丟失,則快重傳后,一個rtt后收到的第一個ack會確認快重傳啟動之前全部已經發送的數據包。但是如果發送窗口中多個包丟失,那么快重傳后第一個收到的ack只能確認發送窗口中的部分數據,稱為“部分確認”。NewReno處理“部分確認”的方法是,認為那個包丟失並重傳那個包。
NewReno新的快重傳/快恢復算法:
1.當收到3次重復ACK,並且發送者並不處於快恢復過程時,
設置ssthresh = cwnd/2
記錄recover=max sequence number,快重傳算法之前已傳輸的最大的數據包序列號(包10或更大)。
2.重傳丟失包(包5),設置cwnd=ssthresh+3
3.如果繼續收到重復ACK(包5),cwnd=cwnd+1
4.發送包(由於上一步cwnd窗口擴張)
5.當收到新的數據包的ACK(包7或包9),這個ACK可能是對第2步重傳或稍后的重傳的確認。
if (ACK確認所有的從丟失包一直到並包括“recover”的數據包)
設置cwnd=ssthresh或min (ssthresh, FlightSize + MSS),然后退出快恢復階段。
else
重傳下一個沒有被確認的數據包;將cwnd=cwnd-新確認的數據包個數+1,發送新的包。這樣縮小窗口的目的是,當快恢復算法最終退出時,大約有ssthresh數量的數據包存在於網絡中。如果收到新的ack,重復執行第3-4步。
總結:
TCP NewReno RFC文檔鏈接http://www.faqs.org/rfcs/rfc2582.html
有理解錯誤的地方,歡迎指出。