擁塞控制:
發送端主動控制cwnd,有慢啟動(從cwnd初始為1開始啟動,指數啟動),擁塞避免(到達ssthresh後,為了避免擁塞開始嘗試線性增長),快重傳(接收方每收到一個封包段都要回複一個目前最大連續位置的确認,發送方隻要一連收到三個重複确認就知道接收方丢包了,快速重傳丢包的封包,并TCP馬上把擁塞視窗 cwnd 減小到1),快恢複(直接從ssthresh線性增長)。
如果網絡上的延時突然增加,那麼TCP對這個事作出的應對隻有重傳資料,但是重傳會導緻網絡的負擔更重,于是會導緻更大的延遲以及更多的丢包,這個情況就會進入惡性循環被不斷地放大。
試想一下,如果一個網絡内有成千上萬的TCP連接配接都這麼行事,那麼馬上就會形成“網絡風暴”,TCP這個協定就會拖垮整個網絡。是以TCP不能忽略網絡上發生的事情,而無腦地一個勁地重發資料,對網絡造成更大的傷害。對此TCP的設計理念是:TCP不是一個自私的協定,當擁塞發生的時候,要做自我犧牲。就像交通阻塞一樣,每個車都應該把路讓出來,而不要再去搶路了。
慢啟動
隻有在TCP連接配接建立和網絡出現逾時時才使用。每經過一個傳輸輪次,擁塞視窗 cwnd 就加倍。一個傳輸輪次所經曆的時間其實就是往返時間RTT。
不過“傳輸輪次”更加強調:把擁塞視窗cwnd所允許發送的封包段都連續發送出去,并收到了對已發送的最後一個位元組的确認。
另外,慢開始的“慢”并不是指cwnd的增長速率慢,而是指在TCP開始發送封包段時先設定cwnd=1,使得發送方在開始時隻發送一個封包段(目的是試探一下網絡的擁塞情況),然後再逐漸增大cwnd。
為了防止擁塞視窗cwnd增長過大引起網絡擁塞,還需要設定一個慢開始門限ssthresh狀态變量(如何設定ssthresh)。
慢開始門限ssthresh的用法如下:
- 當 cwnd < ssthresh 時,使用上述的慢開始算法。
- 當 cwnd > ssthresh 時,停止使用慢開始算法而改用擁塞避免算法。
- 當 cwnd = ssthresh 時,既可使用慢開始算法,也可使用擁塞控制避免算法。
擁塞避免算法:
讓擁塞視窗cwnd緩慢地增大,即每經過一個往返時間RTT就把發送方的擁塞視窗cwnd加1,而不是加倍。
這樣擁塞視窗cwnd按線性規律緩慢增長,比慢開始算法的擁塞視窗增長速率緩慢得多。

無論在慢開始階段還是在擁塞避免階段,隻要發送方判斷網絡出現擁塞(其根據就是沒有收到确認),就要把慢開始門限ssthresh設定為出現擁塞時的發送方視窗值的一半(但不能小于2)。然後把擁塞視窗cwnd重新設定為1,執行慢開始算法。
這樣做的目的就是要迅速減少主機發送到網絡中的分組數,使得發生擁塞的路由器有足夠時間把隊列中積壓的分組處理完畢。
- 當TCP連接配接進行初始化時,把擁塞視窗cwnd置為1。前面已說過,為了便于了解,圖中的視窗機關不使用位元組而使用封包段的個數。慢開始門限的初始值設定為16個封包段,即 cwnd = 16 。
- 在執行慢開始算法時,擁塞視窗 cwnd 的初始值為1。以後發送方每收到一個對新封包段的确認ACK,就把擁塞視窗值另1,然後開始下一輪的傳輸(圖中橫坐标為傳輸輪次)。是以擁塞視窗cwnd随着傳輸輪次按指數規律增長。當擁塞視窗cwnd增長到慢開始門限值ssthresh時(即當cwnd=16時),就改為執行擁塞控制算法,擁塞視窗按線性規律增長。
- 假定擁塞視窗的數值增長到24時,網絡出現逾時(這很可能就是網絡發生擁塞了)。更新後的ssthresh值變為12(即變為出現逾時時的擁塞視窗數值24的一半),擁塞視窗再重新設定為1,并執行慢開始算法。當cwnd=ssthresh=12時改為執行擁塞避免算法,擁塞視窗按線性規律增長,每經過一個往返時間增加一個MSS的大小。
強調:“擁塞避免”并非指完全能夠避免了擁塞。
利用以上的措施要完全避免網絡擁塞還是不可能的。“擁塞避免”是說在擁塞避免階段将擁塞視窗控制為按線性規律增長,使網絡比較不容易出現擁塞。
如果發送方設定的逾時計時器時限已到但還沒有收到确認,那麼很可能是網絡出現了擁塞,緻使封包段在網絡中的某處被丢棄。
這時,TCP馬上把擁塞視窗 cwnd 減小到1,并執行慢開始算法,同時把慢開始門限值ssthresh減半。這是不使用快重傳的情況。
快重傳算法首先要求接收方每收到一個失序的封包段後就立即發出重複确認(為的是使發送方及早知道有封包段沒有到達對方)而不要等到自己發送資料時才進行捎帶确認
接收方收到了M1和M2後都分别發出了确認。現在假定接收方沒有收到M3但接着收到了M4。顯然,接收方不能确認M4,因為M4是收到的失序封包段。
根據可靠傳輸原理,接收方可以什麼都不做,也可以在适當時機發送一次對M2的确認。
但按照快重傳算法的規定,接收方應及時發送對M2的重複确認,這樣做可以讓發送方及早知道封包段M3沒有到達接收方。
發送方接着發送了M5和M6。接收方收到這兩個封包後,也還要再次發出對M2的重複确認。
這樣,發送方共收到了接收方的四個對M2的确認,其中後三個都是重複确認。
快重傳算法還規定,發送方隻要一連收到三個重複确認就應當立即重傳對方尚未收到的封包段M3,而不必繼續等待M3設定的重傳計時器到期。
由于發送方盡早重傳未被确認的封包段,是以采用快重傳後可以使整個網絡吞吐量提高約20%。
與快重傳配合使用的還有快恢複算法,其過程有以下兩個要點:
- 當發送方連續收到三個重複确認,就執行“乘法減小”算法,把慢啟動門限ssthresh減半。這是為了預防網絡發生擁塞。請注意:接下去不執行慢開始算法。
- 由于發送方現在認為網絡很可能沒有發生擁塞,是以與慢開始不同之處是現在不執行慢開始算法(即擁塞視窗cwnd現在不設定為1),而是把cwnd值設定為慢開始門限ssthresh減半後的數值,然後開始執行擁塞避免算法(“加法增大”),使擁塞視窗緩慢地線性增大。
上圖給出了快重傳和快恢複的示意圖,并标明了“TCP Reno版本”。差別:新的 TCP Reno 版本在快重傳之後采用快恢複算法而不是采用慢開始算法。
發送方視窗的上限值 = Min [ rwnd, cwnd ]
- 當rwnd < cwnd 時,是接收方的接收能力限制發送方視窗的最大值。
- 當cwnd < rwnd 時,則是網絡的擁塞限制發送方視窗的最大值。