HarmonyOS-ArkUI Web控件基礎鋪墊1-HTTP協議-數據包內容-CSDN博客
HarmonyOS-ArkUI Web控件基礎鋪墊2-DNS解析-CSDN博客
HarmonyOS-ArkUI Web控件基礎鋪墊3--TCP協議- 從規則本質到三次握手-CSDN博客
HarmonyOS-ArkUI Web控件基礎鋪墊4--TCP協議- 斷聯-四次揮手解析-CSDN博客
HarmonyOS-ArkUI Web控件基礎鋪墊5--TCP協議- 動畫展示超時重傳,滑動窗口,快速重傳-CSDN博客
之前我們已經對TCP的三握四揮,重傳, 和滑動窗口的推理過程進行了講解,本文的流暢理解均建立在以上三篇文章涉及的內容之上。如果對TCP不太了解,建議直接從HarmonyOS-ArkUI Web控件基礎鋪墊3--TCP協議- 從規則本質到三次握手-CSDN博客開始閱讀。
流量控制與擁塞控制關系
這兩個概念我們一塊簡略解釋下。因為流量控制和擁塞控制有聯系。我們需要在最初就要了解為什么滑動窗口總是和流量控制,擁塞控制一塊出現。
流量控制:就是控制發送方的發送速率,不要太快,讓接收方來得及處理數據。通常情況下我們希望數據發送的越快越好,但是實際上如果發送方發送的數據太快,接收方可能來不及接收,就會造成數據的丟失。具體操作是,利用算法,算出流量控制的窗口大小,從而影響滑動窗口大小,來調整發送接收速率。
擁塞控制:就是防止過多的數據注入到網絡中,導致網絡過載。注意流量控制欲擁塞控制的區別,流量控制一般是點對點的控制。而擁塞控制是一個全局性的過程,涉及所有的主機和路由器等待。具體操作依然是利用算法,算出擁塞控制的窗口大小,從而影響滑動窗口的大小。
流量控制與擁塞控制的協作方式如圖
為什么要進行流量控制
流量控制的由來我們前文實際上介紹了一點。滑動窗口機制就是實現流量控制的重要機制。下面是最原始的流水線協議傳輸過程,沒有流量控制:
這種是比較野蠻的傳輸方式,發送端不知道接收端的處理能力,就發送數據,如果接收方的處理能力很差,會導致很多數據包被浪費,是很不合理的。其中接收端處理能力不行有多方原因:
- 接收端本身硬件就不支持快速的傳輸。它可能處于低帶寬網絡環境中。
- 接收端接收到數據,但是數據消費太慢。例如您用HTTP協議讀取下載內容,結果由于業務邏輯有不是VIP就限制速度的需求,此時您可能會針對非VIP用戶讀取的很慢。那么就必然導致接收端的數據消費的慢。
- 接收端緩沖區配置不足,無法容納突發流量或者持續高吞吐數據。等等。
滑動窗口的機制,便處理了這種問題。 在HarmonyOS-ArkUI Web控件基礎鋪墊5--TCP協議- 動畫展示超時重傳,滑動窗口,快速重傳-CSDN博客一文中如何演進的我們已經講過。在這里強調的事,流量控制的手段就是滑動窗口。
滑動窗口運作方式
在講流量控制的算法前,我們完善一下滑動窗口機制。在上篇文章里我們著重講了滑動窗口是怎么演化而來的,但是對于滑動窗口的實現方式提及的很少。按照自上而下的學習方式,我們在這里補全滑動窗口的細節。
滑動窗口AB端同步流程
對于滑動窗口可以分為兩類:
- 發送窗口(SWND) 接收窗口(RWND)
- 雙方互為發送端。 所以其實每一方都存在一個發送窗口和接收窗口。
滑動窗口協議之間的同步,主要就是一方的發送方窗口與另一方接收窗口大小的組合策略。
TCP滑動窗口的大小同步是由接收方接收窗口主導,發送方發送窗口自適應的動態過程。其核心機制圍繞接收方的緩沖區狀態和網絡擁塞狀況展開。
TCP協議的窗口大小在每一個數據包中都會見到。無論是發送方還是接收方,無論是發送的數據包還是ACK,全部都要帶。這個窗口的大小值,我們稱為 rwnd。存儲的位置如圖所示,位于WIndow Size字段中。單位為字節!我們在以后的圖中,會以 rwnd值來代表窗口大小。
窗口同步方式如圖所示:
- 在三次握手的時候,第一次和第二次握手雙方發送的數據包rwnd都是2000
- 當接收端接收到前四個數據包數據的時候發現自身數據消費慢,便改動接收窗口為1000,并跟隨ACK發出去
- 發送端接受到ACK,根據ACK中的窗口值,1000, 調整發送端窗口的大小為1000. 并將窗口的起始位置定位到ACK中的seq映射的位置。
窗口為0時
有時候接收方的接收窗口大小會為0,比如:
- 接收方處理能力不足,接收緩沖區滿
- 接收方的應用層延遲處理,導致讀取邏輯阻塞。等等
此時接收方的接收窗口大小會變為0,會依然發送ACK包使得發送方調整發送窗口為0.當發送方發送窗口是0的時候,便不再發送數據了。
此時,發送端會進行零窗口探測。發送端內部會啟動一個持續計時器,默認30-60s, 定期發送數據內容為1字節的探測包來詢問接收方目前的窗口狀態。接收方接收到探測包便返回最新的rwnd值。就這樣重新起開了窗口。
與此同時,當接收方內部的緩存得到釋放后,會向接收方發送一個普通的ACK包,ACK包中的窗口大小為當前支持的窗口大小。這樣發送方接收并解析之后就可以正常發送數據了。
滑動窗口如何滑動
簡單的理解,滑動窗口的滑動位置,為收到的ACK中 ack中所映射的位置。向下移動不就好嘍?--如果這么簡單,那不必專門寫一個小節😂。
我們探討的是,滑動窗口在數據結構上是怎么個移動法。
我們知道,當TCP完成握手的時候,發送端和接收端分別都會開辟緩沖區。對于接收端,這個緩沖區是接收緩沖區。這個大小我查資料,Linux默認為87KB,最小值為4KB,最大值可擴展至6M(高帶寬場景).
然而我們傳輸的數據通常遠遠大于87KB!滑動窗口如果移動的時候,是按照從前到后這樣移動,那肯定到了87KB就指針越界了!所以對于緩沖區的數據結構而言,必須要采取一種可以快速循環快速偏移的方式。來支持滑動窗口.
TCP采取的是環形緩沖區,來確保窗口可以循環復用內存邊界。對于一個窗口而言其數據也有狀態分類,如圖所示。
盡管窗口會滑動,滑動的范圍在于ACK的偏移量。但是窗口是在一個環形緩沖區中滑動的。你可以想象是一個轉圈的圖。
流量控制-rwnd的計算方式
rwnd是Receiver Window的縮寫,就是接收窗口大小的意思。流量控制就是一個計算出rwnd的過程。上文中我們已經介紹了這個值。這個值之后會被參與計算最終接收端的窗口大小。
這個公式還是相當簡單的。也能解釋如果應用層停止read()數據,TCP干脆就不傳輸了,這種現象。因為應用層不read()數據,會導致應用層已讀取的最后字節序號不動, 但是此刻滑動窗口卻會不斷地向后滑,這樣未消費的數據就會越積越多,直到擠壓的窗口空間為0!
這下如果有個下載需求告訴您非VIP用戶,就要讓他慢。知道切入點在哪里了吧😄😄
顯然流量控制最為關注的就是接收端本地的緩存狀況,以及數據消費能力。流量控制先告一段落。我們算出來rwnd基本就達到目的了。。
擁塞控制及cwnd值的計算方法
擁塞控制主要是用來
- 防止過多的數據注入到網絡,避免網絡中的路由器或鏈路過載
- 是一個全局性的過程,涉及到所有主機,路由器以及降低網絡傳輸性能有關的所有因素。
如圖所示:
當發送數據的設備比較多的時候,隨著連接數量的增加,網絡負載加重,則必然會導致擁堵。擁堵會引發發送端超時重傳機制。如果大量的發重傳包,則又會加重網絡負擔。
由于引發問題的設備較多,數量較大,而且傳輸過程中太多不可預測。所以擁塞控制的著力點并不在于統籌所有設備狀況進行管理(事實上這種方式根本不可能實現)。 擁塞控制主要是通過自身試探的方式,來探測出當前的傳輸情況,從而計算擁塞窗口的大小。想象如果每臺設備都探測,則這種機制可以盡量保障他們都能測算出比較科學的數值。
擁塞窗口變量cwnd的計算方式
擁塞窗口計算的是發送端的擁塞窗口大小。與流量控制不一樣,流量控制計算的是接收端的接收窗口。 擁塞窗口是在發送端計算的。發送端在發送數據的時候的確需要知道目前的網絡情況。
擁塞窗口的計算方式比較普遍的是采用Reno算法。其思路如下:
RTT
在了解Reno算法前,先了解下RTT。因為算法需要用到這個。
RTT全稱 round trip time, 是衡量網絡傳輸性能的核心指標。指的是 從發送方發送數據包開始,到收到接收方對改數據包的確認ACK所經歷的時間。這段時間里涵蓋了以下環節的耗時
- 傳播時延:信號在物理鏈路上的傳輸時間(與距離和介質相關,如光纖 vs 衛星)
- 排隊時延:數據包在路由器/交換機緩存中的等待時間(受網絡擁塞程度影響)
- 處理時延:發送/接收端系統處理數據的時間(如內核協議棧處理)
如何判斷網絡擁塞
TCP通過丟包來判斷網絡是否出現擁塞的。具體的丟包場景為
- 1 發送端出現超時丟包,發送端超時重傳中的計時器,時間到了,還沒有收到對應的ACK,則此時認為丟包了。這種情況往往說明網絡擁塞情況是較為嚴重。
- 2 發送端收到3個連續一樣的ACK包,此時代表雖然接收端沒有接收到數據,但是網絡情況比上一個情況好一些。輕微的有些擁堵。
Reno算法
Reno算法整體不復雜,沒有涉及到超級難的公式。主要就是梳理邏輯。針對不同的情況主要包含四種操作。其中有的我們上篇文章已經講過:
- 慢啟動
- 擁塞避免
- 快速重傳 詳見HarmonyOS-ArkUI Web控件基礎鋪墊5--TCP協議- 動畫展示超時重傳,滑動窗口,快速重傳-CSDN博客
- 快速恢復
Reno算法的整體特征為,前期窗口呈指數級增長,之后再線性增長,探測到一定邊緣后便檢測到擁塞,從而再壓低值,使得發送的窗口在一個平穩的波動中。
具體操作是
- 首先開始慢啟動操作, 慢啟動的規則是:最初設定cwnd值為1,則發送窗口因為取 cwnd 和 rwnd的最小值而選擇是1. 發送端就會發送一個數據包出去,自此每一次傳輸輪次,窗口大小都會變成之前的 2倍。 所以慢啟動的窗口大小是按照指數來增長的。
- 但是指數增長后期會爆發式上漲,用來設置窗口大小肯定不合適。Reno給慢開始設定了一個慢啟動門限,叫ssthresh。當cwnd超過這個值之后,就切換成第二種操作--擁塞避免算法。
- 擁塞避免算法具有線性緩慢增長的能力,其具體的規則是,擁塞窗口每次經過一個RTT,大小則會加1。
- 無論是慢啟動環節,還是擁塞避免啟動環節,只要發送端判斷出來網絡擁塞,就會把ssthresh設置為擁塞時發送窗口的一半。
- 如果阻塞原因是超時重傳引發的,則代表網絡狀況比較糟糕,則cwnd值設置為1,重新執行慢啟動操作。
- 如果阻塞原因是收到了三個連續一樣的ack, 則代表出現了輕微擁堵,則縮小幅度也沒必要像超時丟包那么大,同時也可以進行緩慢的增長。于是會開啟兩個操作
- 執行快速重傳操作,前文我們講過。
- 開始啟動快速恢復算法:快速啟動算法也就是避免cwnd值直接設置為1,假定這個值已經增長到了ssthresh的前提下,臨時抬高窗口大小,每當ACK重復包來一次,便抬高1.直到收到下一個新的ACK,窗口值直接降到ssthresh大小,再按照擁塞避免的操作執行。
我們根據上述的流程看一下下圖便可以理解了:
小結
本文主要描述了
- 針對接收方流量控制的數據同步流程與流量窗口 rwnd 計算方式。
- 針對發送方擁塞控制的計算算法,及 cwnd 計算方式。
我們回顧文章開始的,實際發送方發送窗口的大小則按照以下規則計算。