TCP的滑動(dòng)窗口是一個(gè)很重要的概念代虾,也是很晦澀的一個(gè)知識(shí)點(diǎn)谋减。下面就大概介紹下TCP滑動(dòng)窗口為什么出現(xiàn)灿意?它是怎么工作的的估灿?
什么是TCP窗口
首先,要理解缤剧,client和server各自協(xié)議棧都有自己的buffer馅袁,應(yīng)用層讀寫數(shù)據(jù)的源都是協(xié)議棧buffer里。以接收端為例鞭执,應(yīng)用程序調(diào)用read()時(shí),會(huì)從buffer里移走數(shù)據(jù)到用戶空間芒粹,應(yīng)用程序讀的速度越快(read(1024)必然比read(1)要快)兄纺,那么buffer里的內(nèi)容消費(fèi)的越快,buffer也會(huì)越空化漆。那么TCP就可以告訴client估脆,我現(xiàn)在很閑,你可以發(fā)送更多的數(shù)據(jù)來座云。"更多"是多少疙赠?這就說窗口,窗口就是量化接收端和服務(wù)端當(dāng)前能處理數(shù)據(jù)的能力朦拖。
TCP窗口是如何工作的
client和server端建立連接后圃阳,client會(huì)告訴server,自己的"接收窗口"大小(自己能接收多少的數(shù)據(jù)璧帝,受上面所說的buffer影響)捍岳,server端接收到client的"接收窗口"大小,就會(huì)變成server端自己的"發(fā)送窗口"大小。同樣的锣夹,server端告訴client自己的"接收窗口"大小页徐,就會(huì)變成客戶端的"發(fā)送窗口"大小。
為了理解TCP的窗口大小是怎么樣變化的银萍,我們先需要理解它的含義变勇。最簡(jiǎn)單的方式就是認(rèn)為窗口大小"意味著接收方能接收數(shù)據(jù)的大小",這也是說接收端設(shè)備再應(yīng)用程序讀取buffer中數(shù)據(jù)之前贴唇,能從對(duì)端連接處理多少數(shù)據(jù)搀绣。比如說server端窗口大小是360,那么就意味著server端一次只能從客戶端接收不超過360bytes的數(shù)據(jù)滤蝠。當(dāng)server端收到數(shù)據(jù)豌熄,它會(huì)將數(shù)據(jù)放到buffer里,然后server端必須對(duì)這份數(shù)據(jù)做兩件事
1. server端必須發(fā)送一個(gè) ACK 到client端來確認(rèn)數(shù)據(jù)已經(jīng)收到
2. server端必須處理這份數(shù)據(jù)物咳,把它交給對(duì)應(yīng)的應(yīng)用程序
要區(qū)分上面兩件事對(duì)理解窗口很重要锣险,接收方收到數(shù)據(jù)后會(huì)確認(rèn),但是數(shù)據(jù)并不一定是里面就是從buffer里取出的览闰,這是受應(yīng)用層邏輯控制的芯肤。所以很有可能如果接收數(shù)據(jù)過快,而取出數(shù)據(jù)更慢压鉴,就會(huì)導(dǎo)致buffer滿崖咨。一旦這種情況發(fā)生,窗口大小就開始調(diào)整來防止接收方負(fù)載過高油吭。
正是因?yàn)榇翱诖笮〉恼{(diào)整可以用來調(diào)節(jié)數(shù)據(jù)傳輸?shù)乃俾驶鞫祝跃涂梢詫?shí)現(xiàn)TCP的流控,在傳輸層的流控就是典型的例子婉宰,流控對(duì)于TCP的通信是很重要的歌豺,通過增大或者減小窗口的大小,client和server各自確保彼此設(shè)備發(fā)數(shù)據(jù)和收數(shù)據(jù)平衡心包。
通過TCP窗口實(shí)現(xiàn)流控
下面舉一個(gè)例子类咧,來看TCP窗口大小變化怎樣實(shí)現(xiàn)流控。client端和server端已經(jīng)三次握手建立TCP連接蟹腾,總窗口大小是TCP建立連接時(shí)候確定的痕惋。黑色框代表client和server總的窗口大小,紅色框代表實(shí)際可用的窗口大小娃殖。初始化的時(shí)候默認(rèn)client和server總窗口和可用端口分別都是360值戳。另外,假設(shè)Client總共只發(fā)送360bytes數(shù)據(jù)炉爆,所以總窗口大小不會(huì)往前移動(dòng)述寡。
client 發(fā)送140bytes到server端柿隙,Seq=1,Length=140鲫凶;可用窗口大小往前移動(dòng)禀崖,變成260bytes,總窗口大小不變螟炫,依然是360波附。這中間的120是已發(fā)送,等待確認(rèn);
server端收到140bytes昼钻,放入buffer中掸屡,但是應(yīng)用程序很繁忙,只取出100個(gè)字節(jié)然评。這時(shí)候可用窗口大小: 260(360-100)仅财。接著server端要給client發(fā)確認(rèn),Ack=141碗淌,Window=260盏求。黑框左邊緣向前移動(dòng),表示140字節(jié)已經(jīng)確認(rèn)收到亿眠,但是應(yīng)用程序太慢碎罚,處理很忙導(dǎo)致我現(xiàn)在只能處理260bytes(回顧下上面server端收到數(shù)據(jù)要做的兩件事);
client收到來自server端的ack回應(yīng),首先總窗口左邊緣向前移動(dòng)纳像,表示第一步的140bytes server已經(jīng)收到荆烈,剩下260數(shù)據(jù)。接著被告知server的可接收窗口是260竟趾,client就調(diào)整自己的發(fā)送窗口是260憔购,表示一次發(fā)數(shù)據(jù)不能超過260;
client發(fā)送180bytes,可用窗口變成80(260-180)岔帽,等待確認(rèn)發(fā)送的180bytes;
server收到180bytes玫鸟,放入buffer中,應(yīng)用程序依然很繁忙山卦,這次一個(gè)字節(jié)都不處理鞋邑。此時(shí)可用窗口大小:80(260-180)诵次,然后發(fā)180 ack給client账蓉,并告知窗口大小80;
client收到ack,確認(rèn)之前發(fā)送的180已經(jīng)到達(dá)逾一,剩余數(shù)據(jù)還有80字節(jié)铸本。被告知server端接收窗口大小是80,調(diào)整自己的發(fā)送窗口大小為80
client發(fā)送80bytes遵堵,可用窗口變成0(80-80)箱玷,等待確認(rèn)發(fā)送的80bytes;
server收到180bytes怨规,放入buffer中,應(yīng)用程序依然很繁忙锡足,一個(gè)字節(jié)都不處理波丰。此時(shí)可用窗口大小:80(80-80),然后發(fā)80 ack給client舶得,并告知窗口大小0;
client收到ack掰烟,確認(rèn)之前發(fā)送的80已經(jīng)到達(dá)。被告知server端接收窗口大小是0沐批,調(diào)整自己的發(fā)送窗口大小為0纫骑,此時(shí)無論client是否還有數(shù)據(jù)要發(fā)送,都不能再發(fā)了九孩。
總結(jié)
窗口就是量化接收端和服務(wù)端當(dāng)前能處理數(shù)據(jù)的能力先馆。個(gè)人理解,如發(fā)現(xiàn)接收端的窗口越來越小躺彬,或者越來越大煤墙,都可能會(huì)有問題。
1. 接收端的窗口越來越小,那么就是接收端處理不過來(1.發(fā)的程序太快癣疟,太多;2.收的程序太慢深寥,太少;3.發(fā)端帶寬比收端帶寬更大),會(huì)導(dǎo)致接收端發(fā)送給發(fā)送端的窗口變小设预,從而發(fā)送端調(diào)整發(fā)送窗口大小,降低發(fā)送速度犁河,網(wǎng)絡(luò)流量就會(huì)下降鳖枕。
2. 接收端的窗口越來越大,那么就是發(fā)送端處理不過來(1.收的程序太快桨螺,太多;2.發(fā)的程序太慢宾符,太少;3.發(fā)端帶寬比收端帶寬更小),會(huì)導(dǎo)致接收端發(fā)送給發(fā)送端的窗口變大灭翔,從而發(fā)送端調(diào)整發(fā)送窗口大小魏烫,增加發(fā)送速度,網(wǎng)絡(luò)流量就會(huì)升高肝箱。