一、續
當窗口大小為0,意味著緩沖區滿了,此時發送方,就因該暫停發送,發送方會周期性的除法 " 窗口探測包 " ,并不攜帶載荷,這樣的包對于業務不產生影響,只是為了觸發ACK,一旦查詢出來的結果是非0,緩沖區右有空間了,發送方就可以繼續發送.
二、擁塞控制
要限制發送方發送數據的速率
如果當前接收方處理數據的速度非常快,但是中間路徑出現了問題,發送速度再快也沒有用.
木桶效用 : 能裝多殺水,取決于最短的板
針對這種情況,核心思路,把中間的路徑經過的所有設備看作一個整體,通過實驗的方式找到最快的方式.
如果按照某個窗口大小發送數據之后,出現丟包,就視為中間路徑存在擁堵,就減小窗口大小,
沒出現丟包,視為中間路徑不存才擁堵,就增大窗口大小.
這種方案,一方面簡化了問題,另一方面也能很好地適應,當前網絡環境的復雜性.
中間這些節點,什么時候出現擁堵,什么時候不擁堵,都是隨機的
此時按照以上策略,就可以讓發送速率,.動態變化.
總的原則是,流量控制和擁塞控制,誰產生的窗口大小更小,誰說的算.
擁塞控制具體是怎么把窗口大小給試出來的?
1. 慢啟動.剛開始傳輸的數據,速率是比較小的,采用的窗口 (擁塞窗口) 大小也就比較小.此時,網絡的擁堵情況未知,如果上來就很大,可能會出問題.
2. 此時上述傳輸的數據,沒有出現丟包,說明網絡還是通暢的,就要增大窗口大小,此時,增大的方式是按照指數來增長的.
由于慢啟動,.開始的時候,窗口大小非常小,也有可能網絡上就是很暢通,通過指數可以讓上述窗口快速增長,這樣就可以保證效率了.
3. 指數增長,不會一直保持的,可能會增長太快,一下子導致網絡擁堵.
這里引入了一個 "閾值",當擁塞窗口達到閾值后,此時指數增長就變成線性的了.
(線性增長能使當下窗口保持在一個很快的效率,并且不容易丟包.
4. 線性增長也是一直在增長,積累一段時間之后,傳輸速度可能太快,此時還是會引起丟包,一旦出現丟包,就把擁塞窗口重置成最小的值,回到最初的慢啟動的過程(再次指數增長),并且這里也會根據剛才丟包的窗口大小,重新設置指數增長到線性增長的閾值.
三、延時應答
也是基于滑動窗口,是要盡可能在提高一點效率.
結合滑動窗口及流量控制,能夠通過延時應答ACK的方式,把反饋窗口的大小變得更大一點.
核心就在于在允許范圍內,使,窗口盡可能的變大.
接收方收到數據之后,不會立即返回ACK,而是稍等一下,等一下再返回ACK.
等了一會兒,相當于給接收方的應用程序這里,騰出來更多的時間,來消費這里的數據.
也就是等一會兒,讓接受讓先處理一下數據,就會讓緩沖區空余空間變大,然后再發送更多的數據.
延時應答是按照ACK丟了的方式來處理,因為滑動窗口中ACK丟了也不會產生什么影響.
正常每個數據都有ACK,此時就可以隔幾個數據返回一次ACK,
四、捎帶應答
基于延時應答,引入的機制,能夠提升傳輸效率.
修改窗口大小,確實是提高效率的有效途徑.
捎帶應答,就是走另一條路,盡可能的把能合并的數據包進行合并,從而起到提高效率的效果.
正常情況下,服務器返回的ACK和response之間,有一定的時間間隔,此時就得分兩個包發送了.
由于有了延時應答, 服務器收到請求后,要執行業務邏輯,根據請求計算響應.
ACK延時這段時間里,響應數據剛好準備好了,此時就可以把AKC和響應數據合并成一個TCP數據報
本身ACK也不帶載荷,只是把報頭中的ACK標志位設為1,并且設置確認序號以及窗口.
這幾個屬性不會沖突.
五、面向字節流
"粘包問題"
此處的包是 " TCP載荷中的應用數據包"
TCP傳輸的數據到了接收方后,接收方要根據socket api 來?read 出來,read出來的結果就是應用層數據包.
由于整個read過程非常靈活,可能會使代碼中無法區分出當前的數據是從哪到哪是一個完整的應用數據包,
如上圖,就無法確定從哪到哪是一個數據.
解決問題的關鍵,就是"明確包與包之間的邊界"
1. 通過特殊符號,作為分隔符,見到分隔符,就視為一個包結束了
2. 指定出包的長度,比如在包開始的位置,加上一個特殊的空間來表示整個數據的長度.
上述這樣的問題,都應該是在設計應用層協議的時候就設計好了的.
六、異常問題
考慮比丟包更嚴重的情況,甚至說網絡直接出現故障等情況
1. 其中有一方出現了進程崩潰
進程無論是正常結束,還是異常崩潰,都會觸發到回收文件資源,關閉文件這樣的效果(系統自動完成的),就會觸發四次揮手
TCP的生命周期.可以比進程更長一點,雖然進程已經退出了,但是TCP連接還在,仍然可以繼續進行四次揮手.
2. 其中有一方關機了(正常流程)
關機會強制終止所有進程,此時四次揮手不一定能完成
如果夠快,此時,本段和對端都能正確刪除保存的連接信息.
如果不夠快,至少也把第一個FIN發給對方,告訴對方我這里要結束了.
對端收到FIN后,對端也要進入釋放連接的流程了,返回ACK,并且也發FIN,這里發的FIN不會再有ACK了.
FIN沒有收到ACK之后,會進行重傳,達到指定次數后,就單方面釋放連接了.
3. 其中一方出現斷電.
? ?3.1 斷電的是接收方,發送方會突然發現沒有ACK了,就要重傳.
? ? ? ? 重試幾次后還是不行,TCP就會嘗試復位連接.(相當于清楚原來的TCP中的各種臨時數據,重新開始.)
這就需要用到TCP中的一個復位報文段.
通過此處的RST,報文直接復位.
? ? ? ? 3.2 斷電的是發送方
接收方本來在阻塞等待發送方的消息,結果一直沒來.
這是就要區分,發送方是掛了還是沒準備好.
TCP中,接收方一段時間后,沒有收到消息,就會觸發 " 心跳包 " 來詢問對方的情況.
心跳包:不攜帶應用層數據包的特殊數據包,1. 周期的? ?2. 沒有心跳,視為是對端掛了.
如果對端沒有心跳了,此時本端也會嘗試復位并且單方面釋放連接了.
? ?4. 網線斷開.
這種情況本質上就是3的3.1 和 3.2 的結合了.