????????前文已經(jīng)介紹過了TCP滑動窗口大小的重要性。在客戶端與服務器的連接中拱镐,客戶端告知服務器它一次希望從服務器接收多少字節(jié)數(shù)據(jù),這是客戶端的接收窗口持际,即服務器的發(fā)送窗口沃琅。類似地,服務器告知客戶端一次希望從客戶端接收多少字節(jié)數(shù)據(jù)蜘欲,也就是服務器的接收窗口和客戶端的發(fā)送窗口益眉。
????????要理解為什么窗口大小會產(chǎn)生波動,首先需要理解它的含義姥份。最簡單的方式是它代表了設(shè)備對于特定連接的接收緩存大小郭脂。即,窗口大小代表一個設(shè)備一次能夠從對端處理多少數(shù)據(jù)澈歉,之后再傳遞給應用層處理展鸡。
????????當服務器從客戶端接收數(shù)據(jù),它就將數(shù)據(jù)放在緩存中埃难,服務器必須對數(shù)據(jù)做以下兩步操作:
? ??????確認:服務器必須將確認信息發(fā)回客戶端以表明數(shù)據(jù)接收莹弊。
? ??????傳輸:服務器必須處理數(shù)據(jù),將它傳遞給目標應用程序處理涡尘。
????????區(qū)分開這兩件事情是非常重要的忍弛。關(guān)鍵在于基本的滑動窗口機制中,數(shù)據(jù)于接收時確認考抄,但并不一定立即從緩存中傳輸出去细疚。也就意味著當接收數(shù)據(jù)速度快于接收TCP處理速度時,緩存有可能被填滿川梅。當這一情況發(fā)生時疯兼,接收設(shè)備需要調(diào)整窗口大小已防止緩存過載。
????????由于窗口大小能夠以這種方式管理連接兩端設(shè)備數(shù)據(jù)流的速率挑势,TCP就是以這種方式實現(xiàn)流控這一傳輸層非常典型的任務镇防。流控對于TCP來說是很重要的,因為它是設(shè)備間互通狀態(tài)的方式潮饱。通過增加或縮小窗口大小来氧,服務器和客戶端能夠確保對端發(fā)送數(shù)據(jù)的速度等同于處理速度。
減小窗口大小以降低發(fā)送速率:
????????首先看一下客戶端到服務器的數(shù)據(jù)傳輸,如下圖所示
????????客戶端傳輸140字節(jié)數(shù)據(jù)至服務器啦扬。之后中狂,客戶端的可用窗口還剩下220字節(jié):發(fā)送窗口的360字節(jié)減去發(fā)送的140字節(jié)。
????????一段時間過后扑毡,服務器接收到140字節(jié)并將它們放在緩存中∥搁牛現(xiàn)在,理想的情況下瞄摊,140字節(jié)進入緩存勋又,確認之后立刻從緩存移出。也就是說换帜,緩存有足夠的大小來容納客戶端發(fā)送的所有數(shù)據(jù)楔壤。緩存的空閑空間維持在360字節(jié),因此告知客戶端窗口大小保持不變惯驼。
????????只要服務器處理速度和數(shù)據(jù)進入速度相同蹲嚣,窗口大小就會保持在360字節(jié)∷钌客戶端在接收到140字節(jié)的確認信息以及窗口大小保持不變的信息之后隙畜,將360字節(jié)窗口向右移動140字節(jié)。由于現(xiàn)在未確認字節(jié)數(shù)為0说贝,因此客戶端又可以發(fā)送360字節(jié)數(shù)據(jù)议惰。對應于之前可用窗口的220字節(jié),加上剛剛確認的140字節(jié)數(shù)據(jù)乡恕。
????????然而换淆,現(xiàn)實中服務器可能需要處理數(shù)十,數(shù)百乃至數(shù)千個TCP連接几颜。TCP可能無法立刻處理數(shù)據(jù)倍试,或應用應用程序本身無法接收140字節(jié)數(shù)據(jù)。任何一種情況下蛋哭,服務器TCP都無法立刻將140字節(jié)從緩存中移出县习。這時,除了發(fā)回確認信息給客戶端以外谆趾,服務器會想要告知客戶端更改窗口大小躁愿,以表示緩存已經(jīng)被部分寫入了。
????????假設(shè)我們接收到140字節(jié)沪蓬,但只能發(fā)送40字節(jié)給應用程序彤钟,緩存中剩下100字節(jié)。當發(fā)送140字節(jié)的確認信息跷叉,服務器將發(fā)送窗口縮小100字節(jié)逸雹,至260字節(jié)营搅。當客戶端從服務器接收到這一片段,它將會看到140字節(jié)的確認信息并將窗口向右滑動140字節(jié)梆砸。在滑動過程中转质,將大小縮減至260字節(jié)√溃可以認為將窗口左端滑動140字節(jié)休蟹,但右端僅滑動40字節(jié)。新的稍小一些的窗口保證服務器從客戶端接收最多260字節(jié)數(shù)據(jù)日矫,以適應接收緩存中的剩余空間赂弓,如下圖的1-3步所示
縮減發(fā)送窗口以停止發(fā)送新數(shù)據(jù):
????????如果服務器無法接收任何新數(shù)據(jù)會怎么樣呢?假設(shè)客戶端下一次傳輸180字節(jié)哪轿,但是服務器太忙碌而無法對其進行處理拣展。這種情況下,服務器將這180字節(jié)緩存下來缔逛,并且在確認信息中,將窗口大小從260字節(jié)縮減為80字節(jié)姓惑。當客戶端接收到180字節(jié)的確認信息褐奴,它也會看到窗口縮減了180字節(jié),它會滑動與縮減同樣的大小于毙,告知服務器:我確認接收180字節(jié)數(shù)據(jù)敦冬,但不允許你再發(fā)送新的數(shù)據(jù)。也可以看作窗口左端滑動180字節(jié)唯沮,但右端維持不動脖旱。只要右端不移動,客戶端就無法發(fā)送更多數(shù)據(jù)介蛉。這一過程顯示在上圖的4-6中萌庆。
關(guān)閉發(fā)送窗口:
????????窗口調(diào)整可以通過雙方設(shè)備來完成。如果服務器從客戶端接收的數(shù)據(jù)持續(xù)快于推送給應用的速率币旧,則服務器將會繼續(xù)減小接收窗口践险。假設(shè)發(fā)送窗口減小至80字節(jié),客戶端發(fā)送第三個請求吹菱,長度為80字節(jié)巍虫,但服務器仍處于繁忙狀態(tài)。之后服務器將窗口減小為0鳍刷,也稱為關(guān)閉窗口。這一信息告知客戶端服務器已經(jīng)過載瓦胎,它需要徹底停止發(fā)送數(shù)據(jù)凛捏,如上圖最后一步所示担忧。之后,當服務器負載減輕時惩猫,可以再次增加這一連接的窗口,允許更多數(shù)據(jù)傳輸奶镶。