滑動窗口的單位是字節。其值能夠爲MSS*N(mss的整數倍)算法
若是咱們在任一時間點對於這一過程作一個「快照」,那麼咱們能夠將TCP buffer中的數據分爲如下四類,並把它們看做一個時間軸:緩存
注意: 在tcp的一次報文傳輸過程當中,會發送多個字節,其做爲一個總體,對端只會對此報文的最後一個字節進行ack,代表此報文的全部字節都接收成功。相應的,客戶端也會將這些字節放入狀態2,滑動窗口往前移動。服務器
實際的發送窗口,是min(cwnd, wnd).這就保證了網絡
- 發送的流量不會超過服務器緩存剩餘的空間
- 發送的流量不會超過當前網絡鏈路的負荷
這裏爲了表述簡單,咱們將擁塞窗口大小稱爲N,N的值爲N mss字節.
tcp的擁塞控制主要有4個算法ssh
關於慢啓動的ssthresh值,有篇文章講的比較好。TCP核心概念-慢啓動,ssthresh,擁塞避免,公平性的真實含義,同時也剪藏在evernote中。tcp
疑問: 爲何2*N = wnd
咱們假設當前的N爲4,即:當前的TCP鏈路可承載4字節的信息。那麼,咱們該將wnd設置爲多大,才能充分利用此鏈路呢?
充分利用鏈路,就是說,此鏈路充滿數據,服務器從接收一個,客戶端發送一個,數據流不斷。
可見,在理想的狀況下,當wnd=8的時候,客戶端不用等待ack能夠一直髮送數據,不然客戶端須要收到ack並將滑動窗口向前移動,才能發送新的數據。
注意: 在一個rtt中,共發送了wnd 字節的流量。spa
初始化cwnd=1, 在每收到一個對新的報文段的確認後,把擁塞窗口增長至多一個MSS的數值。用這樣的方法逐步增大發送方的擁塞窗口 cwnd ,可使分組注入到網絡的速率更加合理。.net
當cwnd<ssthresh時,採用慢啓動算法,當cwnd>ssthresh時,採用擁塞避免算法。
那麼這個值具體的有什麼講究呢?這個在上面的連接中講的比較清楚了,我把我本身的理解再簡單的闡述一下。
ssthresh代表了當前網絡鏈路中可容納的最大字節數。當新建tcp連接的時候,並不清楚此tcp鏈路的情況,因此將sshthresh設置爲一個巨大的值。而後每收到一個報文的ack,都將cwnd的值加1。所以,通過一個rtt, cwnd是呈指數級在增加。code
可是通常來講cwnd是達不到初始 ssthresh的值的,在cwnd增加的過程當中,可能初始ssthresh的值遠遠大於鏈路的帶寬,所以很快鏈路就會出現阻塞。注意這裏區分兩種狀況:blog
當前的cwnd值過大,根本緣由是咱們假定當前鏈路的承載能力ssthresh過大,須要縮減,ssthresh = cwnd/2,就是說,在當前的cwnd狀況下,其對應的ssthresh_new爲 cwnd/2。所以咱們將ssthresh_old替換爲ssthresh_new,即減爲當前cwnd值得一半,並開始新一輪的迫近過程。
舉個例子
理論狀況:ssthresh=2 cwnd=4 初始化: ssthresh=5 cwnd=1 rtt1: ssthresh 5 cwnd=1 rtt2: ssthresh 5 cwnd=2(cwnd==ssthresh,改成擁塞避免算法) rtt3: ssthresh 5 cwnd=3 rtt4: ssthresh 5 cwnd=4 rtt5: ssthresh 5 cwnd=5 rtt6: ssthresh 5 cwnd=6(可能開始出現阻塞丟包) rtt7: ssthresh 3 cwnd=1(reset) ...
疑問:那會不會存在cwnd/2>ssthresh_old的狀況呢?這樣不是ssthresh反而加大了?
wnd = rtt*r
在一個rtt中,共發送了wnd 字節的流量。若是這wnd字節的流量都成功ack,那麼咱們將cwnd+1
即:一個rtt 結束後,沒有網絡阻塞的話 ,cwnd+1。
能夠很明顯看到擁塞避免和慢啓動的差別,慢啓動時一個rtt後,cwnd增長一倍。