慢啓動和擁塞避免算法是在 1988 年提出的,而快重傳和快恢復是 1990 年提出的;
既然這兩個新算法是時隔兩年後才提出的,那麼它一定是對慢啓動和擁塞避免算法的不足之處進行了改良;
在此之前,先來回憶一下,發送方如何判定網絡產生擁塞?已知的一種情況是對方回覆 ack 超時;
其實還有一種情況,如果發送方連續收到接收方多個重複的 ack(接收方不會沒事發送重複的 ack 的),則說明網絡生產擁塞;
那麼簡單總結一下,發送方判定網絡擁塞就有兩種情況了:
- ack 超時
- 發送方連續收到重複的 ack
知道了上面的事情後,接下來看看,針對連續收到重複的 ack,發送方應該怎麼做;
快重傳
首先對於接收方來說,如果接收方收到一個失序的報文段,就立即回送一個 ACK 給發送方,而不是等待一會然後發送延時的ACK(請參考《遲到的 ACK》);
所謂失序的報文是指,用戶沒有按照順序收到 TCP 報文段,比如接收方收到了報文 M1, M2, M4,那麼 M4 就稱爲失序 報文。
這樣做的目的是可以讓發送方儘可能早的知道報文段 M3 未到達接收方;
快重傳算法規定,如果發送方一連收到 3 個重複的確認,就應當立即傳送對方未收到的報文 M3,而不必等待 M3 的重傳計時器到期;
圖1 快重傳算法
快恢復
在學習了上一節的慢啓動和擁塞避免算法後,我們知道,一旦出現超時重傳,TCP 就會把慢啓動門限 ssthresh 的值設置爲 cwnd 值的一半,同時 cwnd 設置成 1;
但是快恢復算法不這樣做;
一旦出現超時重傳,或者收到第三個重複的 ack 時(快重傳),TCP 會把慢啓動門限 ssthresh 的值設置爲 cwnd 值的一半,同時 cwnd = ssthresh (在有些版本中,會讓 cwnd = ssthresh + 3)。
之前的舊版本的算法是在 TCP 的 Tahoe 版本中,而改進的版本算法是在 TCP Reno 版本中;
圖 2 中演示了他們之間的區別:藍色曲線是舊版本,而紅色是新版本;
圖 2 中,連續收到三個重複ACK後,TCP Reno(紅色)版本轉入了擁塞階段,而 TCP Tahoe 版本(藍色)轉入了慢啓動階段;
實際上,現代的 Linux 內核版本早已都不採用上面這些 TCP 版本了,而是使用使用的 TCP Cubic 版本。那爲什麼還要學呢?這就好比你想學會走,你就得先學會爬,簡單的先弄會,以後再自學複雜的
流量控制與擁塞控制
在學習流量控制的時候,我們假設網絡無限好,不擁塞;
在學習擁塞控制的時候,我們又假設接收方緩衝區和接收窗口無限大,對數據來者不拒。現在,是時候綜合考慮他們的時候了。
如何綜合考慮這兩者呢?實際上很簡單,我們只要將接收方的窗口 rwnd 和擁塞窗口 cwnd 放在一起比較,取兩者中的較小者,也就是:
上式指出:
- rwnd < cwnd : 是接收方的接收能力限制了發送方窗口的最大值;
- cwnd < rwnd : 是網絡的擁塞限制了發送方窗口的最大值;
- 擁塞窗口cwnd是在發送方這邊,因爲它的值反映了網絡的擁塞狀況;