現在網絡上大部分的網絡請求都是以TCP的方式進行傳輸的了。網絡鏈路是固定的,各種鏈路情況也是不一樣的。網絡擁堵一直是TCP協議設計和使用的時候盡力要避免的。比如,從TCP協議的網絡包協議設計來看,TCP使用一發一答的ACK的網絡包確認方式,而不是使用NAK這種會增加確認包的方式來做確認機制。這個就是在盡力降低網絡上的包傳遞數量,避免網絡擁堵。
還有哪些控制網絡擁堵的方式呢?
當一個連接連接上網絡的時候,並不應該一次向網絡中就發送大量的數據包,否則的話,如果網絡鏈路狀況不是很好的情況,這些網絡包可能會加重網絡擁堵的情況。所以最初TCP連接建立之後,發送網絡包的大小是逐漸增長的,最開始是1個最大報文大小,然後是指數級增長。這個就是慢啟動機制。
但是到了一個數值,就不能再進行指數增長了,這個時候,網絡包增長就從指數增長改成線性增長,就是一次增加一個MSS。這個就是擁塞避免階段。
如果互聯網上傳遞的都是小包,那絕對是個災難,每個網絡請求都耗費比較大的資源,如果一份數據分為零零散散很多份小包,每個網絡傳輸都只傳輸一個小包,那麼是典型的浪費資源,增加擁堵。糊塗窗口綜合症就是發送方和接收方糊裡糊塗達成的協商是傳送小包。
為了解決這個問題,很多方法應運而生,Nagle算法就是其中一個方法。
Nagle算法規定了,發送方網絡鏈路上一個連接只能有一個未獲得ACK的請求包。這個就意味著,發送方只有等待上一個請求的ACK回來之後才能發送下一個請求,這樣兩個請求過程中間,發送方的緩存區就存儲了足夠滑動窗口大小的包進行傳遞,這樣就有效避免了大量的小包產生。
另外一種解決糊塗窗口綜合症的方法就是Cork算法。這個算法比Nagle算法更激進一些,干脆直接計算出一個值,當發送方的滑動窗口大小小於這個值的時候,不進行數據包的發送。這樣這個算法就能有效直接杜絕小包的出現了。當然可能會導致數據有一定的延遲性了。
Nagle和Cork算法都是在發送方進行控制,兩個算法的著重點不同,Cork算法著重點在於避免小包,更多是端到端的優化。Nagle算法則是為了提高網絡的利用率。
從接收方也有能力防止糊塗窗口綜合症。延遲ACK算法就是接收方並不是收到請求之後立刻發送ACK,而是開啟一個計時器,等到計時器結束的時候,才發送ACK。或者是接收方在需要回發送請求的時候,順帶著把上個請求的ACK發送回去了。這個機制如果配合Nagle算法,能讓連接的滑動窗口達到一個預期的比較好的值。
上面都是防止阻塞的方法,但是萬一阻塞了呢?發出去的請求包在規定時間內沒有收到ACK,不管是請求包丟失,還是ACK包丟失,還是網絡延遲,總之,這裡都是需要有個重傳機制的。TCP的重傳機制有兩種:超時重傳和快速重傳。
說白了就是在請求包發出去的時候,開啟一個計時器,當計時器達到時間之後,沒有收到ACK,則就進行重發請求的操作,一直重發直到達到重發上限次數或者收到ACK。
還有一種機制就是快速重傳,當接收方收到的數據包是不正常的序列號,那麼接收方會重復把應該收到的那一條ACK重復發送,這個時候,如果發送方收到連續3條的同一個序列號的ACK,那麼就會啟動快速重傳機制,把這個ACK對應的發送包重新發送一次。具體可以參考: