慢啟動、擁塞避免、超時重傳、快速重傳、快速恢復、滑動視窗
流量控制
因為資料的傳送方和接收方並不一定具有相同的資料處理能力,為了避免資料傳送方的資料傳送過快,而導致其超過了接受端的資料處理能力,TCP採用了流量控制機制,接收方在TCP的包頭裡面採用16位RWND,通告發送方自己的接收視窗,也就是還能夠接收的最多的資料量,這樣傳送端就不會過度發包而超過接收方的接收能力。
滑動視窗:TCP流量控制的一種手段。這裡說的視窗是指接收通告的視窗(RWND),告知對方本端的TCP接收緩衝區還能容納多少位元組的資料,對方就可以控制傳送資料的速度。
擁塞:當網路中存在過多的報文時,網路的效能就會相應下降,這種現象就被成為擁塞。
TCP擁塞控制
擁塞視窗CWND
傳送視窗SWND:擁塞控制最終受控變數是傳送端向網路一次連續寫入的資料量,即傳送視窗(SWND),TCP報文段的最大長度(資料部分)稱為SMSS,其值一般等於MSS(MTU-40,20位元組的IP頭和20位元組的TCP頭)。傳送端需要合理的選擇SWND的大小,如果太小,會引起明顯的網路延遲,反之,則容易導致網路擁塞。TCP的擁塞控制主要原理依賴於一個擁塞視窗來控制。實際的SWND=min(RWND,CWND)。關於CWND的單位,在TCP中是以位元組來做單位的,我們假設TCP每次傳輸都是按照MSS大小來發送資料的,因此你可以認為CWND按照資料包個數來做單位也可以理解,所以有時我們說CWND增加1也就是相當於位元組數增加1個MSS(在TCP連線建立時,收發雙方協商通訊時每一個報文段所能承載的最大資料長度)大小。
<1>慢啟動:最初的TCP在連線建立成功後會向網路中傳送大量的資料包,這樣很容易導致網路中路由器快取空間耗盡,從而發生擁塞。因此新建立的連線不能夠一開始就大量傳送資料包,而只能根據網路情況逐步增加每次傳送的資料量,以避免上述現象的發生。具體來說,當新建連線時,CWND初始化為2~4個MSS大小,傳送端開始按照擁塞視窗大小發送資料,每當有一個報文段被確認,CWND就增加1個MSS大小。這樣CWND的值就隨著網路往返時間(Round Trip Time,RTT)呈指數級增長,事實上,慢啟動的速度一點也不慢,只是它的起點比較低一點而已。我們可以簡單計算下:
開始 ---> CWND= 1
經過1個RTT後 ---> CWND = 1+1 = 2 //1*2
經過2個RTT後 ---> CWND= 2+2 = 4 //2*2
經過3個RTT後 ---> CWND= 4+4 = 8 //4*2
如果頻寬為W,那麼經過RTT*log2W時間就可以佔滿頻寬。
<2>擁塞避免:從慢啟動可以看到,CWND可以很快的增長上來,從而最大程度利用網路頻寬資源,但是CWND不能一直這樣無限增長下去,一定需要某個限制。TCP使用了一個叫慢啟動門限(ssthresh)的變數,當CWND超過該值後,慢啟動過程結束,進入擁塞避免階段。擁塞避免的主要思想是加法增大,也就是CWND的值不再指數級往上升,開始加法增加。此時當視窗中所有的報文段都被確認時,CWND的大小加1,CWND的值就隨著RTT開始線性增加,這樣就可以避免增長過快導致網路擁塞,慢慢的增加調整到網路的最佳值。
上面討論的兩個機制都是沒有檢測到擁塞的情況下的行為,那麼當發現擁塞了CWND又該怎樣去調整呢?
從整體上來講,TCP擁塞控制視窗變化的原則是加法增大、乘法減小。可以看出TCP的該原則可以較好地保證流之間的公平性,因為一旦出現丟包,那麼立即減半退避,可以給其它新建的流留有足夠的空間,從而保證整個網路的公平性。
<3>超時重傳:TCP協議在傳送資料以後,每一個報文段都會有一個重傳定時器(RTO),在定時器指定的時間內接收端對於這個報文的確認報文如果沒有到達,則會重新發送一次,並且這次的定時器時間為上次的兩倍。
把ssthresh設定為max(已經發送但是未收到確認的位元組數/2,2*MSS)
重新進入慢啟動過程。
<4>快速重傳:那就是連續收到3個相同的ACK。TCP利用3個相同的ACK來判定資料包的丟失,此時進行快速重傳,快速重傳做的事情有:
把ssthresh設定為max(已經發送但是未收到確認的位元組數/2,2*MSS)
把CWND再設定為ssthresh的值(具體實現有些為ssthresh+3*MSS)
每收到一個重複的ack時,就將CWND設定為CWND+MSS
收到新的ack就將CWND設定為ssthresh
重新進入擁塞避免階段。
<5>快速恢復:快速恢復演算法是在上述的“快速重傳”演算法後新增的,當收到3個重複ACK時,TCP最後進入的不是擁塞避免階段,而是快速恢復階段。快速重傳和快速恢復演算法一般同時使用。快速恢復的思想是“資料包守恆”原則,即同一個時刻在網路中的資料包數量是恆定的,只有當“老”資料包離開了網路後,才能向網路中傳送一個“新”的資料包,如果傳送方收到一個新的ACK,那麼根據TCP的ACK機制就表明有一個數據包離開了網路,於是CWND加1。如果能夠嚴格按照該原則那麼網路中很少會發生擁塞,事實上擁塞控制的目的也就在修正違反該原則的地方。
快速恢復的主要步驟是:
①當收到3個重複ACK時,把ssthresh設定為CWND的一半,把cwnd設定為ssthresh的值加3,然後重傳丟失的報文段,加3的原因是因為收到3個重複的ACK,表明有3個“老”的資料包離開了網路。
②再收到重複的ACK時,擁塞視窗增加1。
③當收到新的資料包的ACK時,把CWND設定為第一步中的ssthresh的值。原因是因為該ACK確認了新的資料,說明從重複ACK時的資料都已收到,該恢復過程已經結束,可以回到恢復之前的狀態了,也即再次進入擁塞避免狀態。
<6>選擇性應答(SACK):比如序號1,2,3,5,7的資料收到了,那麼普通的ACK只會確認序列號4,而SACK會把當前的5,7已經收到的資訊在SACK選項裡面告知對端,從而提高效能,當使用SACK的時候,因為SACK本身攜帶的資訊就可以使得傳送方有足夠的資訊來知道需要重傳哪些包,而不需要重傳哪些包。