TCP 的流量控制與擁塞控制可以說是一體的。流量控制是通過滑動窗口實現的,擁塞避免主要包含以下2個內容:
(1)慢開始,擁塞避免
(2)快重傳,快恢復
1.流量控制——滑動窗口
TCP采用大小可變的滑動窗口進行流量控制,窗口大小的單位是字節。
發送窗口在連接建立時由雙方商定。但在通信的過程中,接收端可根據自己的資源情況,隨時動態地調整對方的發送窗口上限值(可增大或減小)。
為什么要設置窗口?
我們可以把窗口理解為緩沖區(但是有些窗口和緩沖區又不太一樣)。
如果沒有這些“窗口”,那么TCP沒發送一段數據后都必須等到接收端確認后才能發送下一段數據,這樣做的話TCP傳輸的效率實在是太低了。
解決的辦法就是在發送端等待確認的時候繼續發送數據,假設發送到第X個數據段是收到接收端的確認信息,如果X在可接受的范圍內那么這樣做也是可接受的。這就是窗口(緩沖區)引入的緣由。
1.1 窗口
(1)接收端窗口 rwnd
接收端緩沖區大小。接收端將此窗口值放在 TCP 報文的首部中的窗口字段,傳送給發送端。
(2) 擁塞窗口 cwnd (congestion window)
發送端緩沖區大小
(3)發送窗口swnd
發送窗口的上限值 = Min [rwnd, cwnd]
當 rwnd < cwnd 時,是接收端的接收能力限制發送窗口的最大值。
當 cwnd < rwnd 時,則是網絡的擁塞限制發送窗口的最大值。
1.2 滑動窗口
發送端已發送了 400 字節的數據,但只收到對前 200 字節數據的確認,同時窗口大小不變。還可發送 300 字節。

發送端收到了對方對前 400 字節數據的確認,但對方通知發送端必須把窗口減小到 400 字節。現在發送端最多還可發送 400 字節的數據。
2. 擁塞控制
2.1 慢開始和擁塞避免
2.1.1 慢開始原理
(1)在主機剛剛開始發送報文段時可先將擁塞窗口 cwnd 設置為一個最大報文段 MSS 的數值。
(2)在每收到一個對新的報文段的確認后,將擁塞窗口增加至多一個 MSS 的數值。
(3)用這樣的方法逐步增大發送端的擁塞窗口 cwnd,可以使分組注入到網絡的速率更加合理。
2.1.2 實例講解

注:圖中窗口的單位都是報文段
(1)當 TCP 連接進行初始化時:
發送窗口:swnd = 1
慢開始閾值:ssthresh = 16
(2)發送端收到 ACK1 (確認 M0,期望收到 M1)后,將 cwnd 從 1 增大到 2,於是發送端可以接着發送 M1 和 M2 兩個報文段(指數增長)
(3)接收端發回 ACK2 和 ACK3。發送端每收到一個對新報文段的確認 ACK,就把發送端的擁塞窗口加 1。現在發送端的 cwnd 從 2 增大到 4,並可發送 M4 ~ M6共 4個報文段。(指數增長)
(4)當swnd >= ssthresh,swnd執行擁塞避免算法,swnd窗口按線性規律增長。 (加法增大)
(5)當發送 超時,此時swnd = 24 :
ssthresh = swnd/2 = 12;(乘法減小)
swnd = 1
(6)重復地2步。
2.2 快重傳和快恢復
2.2.1 快重傳
發送端只要一連收到三個重復的 ACK 即可斷定有分組丟失了,就應立即重傳丟失的報文段而不必繼續等待為該報文段設置的重傳計時器的超時
2.2.2 快恢復
(1) 當發送端收到連續三個重復的 ACK 時,就重新設置慢開始門限 ssthresh。
(2) 與慢開始不同之處是 swnd 不是設置為 1,而是設置為 ssthresh + 3 * MSS。
(3) 若收到的重復的 ACK 為 n 個(n > 3),則將 cwnd 設置為 ssthresh + n * MSS。
(4) 若發送窗口值還容許發送報文段,就按擁塞避免算法繼續發送報文段。
(5) 若收到了確認新的報文段的 ACK,就將 swnd 縮小到 ssthresh。