簡介
流量控制是一個 ** 速度匹配服務(wù) ** (匹配發(fā)送方的發(fā)送速率與接收方的讀取速率),因?yàn)榘l(fā)送方發(fā)送數(shù)據(jù)的速率和接收方處理數(shù)據(jù)的速率不一定匹配,當(dāng)發(fā)送方發(fā)送速率大于接收方的處理速率時,就有可能因接收方來不及接收數(shù)據(jù)而導(dǎo)致數(shù)據(jù)丟失。所以 ** 流量控制就是一種用于控制發(fā)送方的數(shù)據(jù)發(fā)送速率以使得接收方能夠來得及接收數(shù)據(jù)的機(jī)制 ** 。
在通信過程中,接收方根據(jù)自己接收緩存的大小,動態(tài)地調(diào)整發(fā)送方的發(fā)送窗口大小,這就是 ** 接收窗口 rwnd **,即調(diào)整 TCP 報文段首部中的“窗口”字段值,來限制發(fā)送方向網(wǎng)絡(luò)注入報文的速率。同時,發(fā)送方會根據(jù)其對當(dāng)前網(wǎng)絡(luò)擁塞程度的估計而確定一個窗口值,稱為 ** 擁塞窗口 cwnd ** ,其大小與網(wǎng)絡(luò)的帶寬和時延密切相關(guān)。最后實(shí)際在網(wǎng)絡(luò)中傳輸?shù)膱笪臄?shù)應(yīng)該rwnd 和 cwnd 中的較小者。
控制算法 -- 滑動窗口協(xié)議
TCP 報文頭部有一個窗口字段,這個字段用于控制發(fā)送方能夠發(fā)送的數(shù)據(jù)量。每發(fā)送一個TCP 報文段,發(fā)送方就能夠通過這個字段就能夠告訴對方當(dāng)前我的接收窗口(rwnd)的大小(也就是我能夠接收的最大字節(jié)數(shù)),然后接收方就應(yīng)該調(diào)整自己的數(shù)據(jù)發(fā)送量不大于該值。
rwnd > 0:表示數(shù)據(jù)接收方所能夠接收的 ** 字節(jié)數(shù) ** ;
rwnd = 0:表示數(shù)據(jù)接收方的緩存區(qū)已滿,不想接收數(shù)據(jù)了,此時發(fā)送方不應(yīng)向網(wǎng)絡(luò)中發(fā)送任何數(shù)據(jù),直至接收方重新發(fā)送一個 rwnd > 0 的 TCP 報文告訴發(fā)送方可以接收數(shù)據(jù)為止。
** 互相等待的死鎖局面 ** :當(dāng)接收方設(shè)置了一個 rwnd = 0 的窗口后,發(fā)送方會停止發(fā)送數(shù)據(jù),等待接收方重新控制接收窗口的大小。然后接收方可以繼續(xù)接收數(shù)據(jù)時,向發(fā)送方發(fā)送一個重新控制窗口的報文段,然后等待發(fā)送方繼續(xù)發(fā)送數(shù)據(jù)。然而可能很不幸地丟失了這個重設(shè)窗口的報文,那么收發(fā)雙方都將處于等待對方傳送數(shù)據(jù)的狀態(tài),由此也就進(jìn)入了收發(fā)雙方相互等待的死鎖局面。
** 解決策略 ** :為了解決收發(fā)雙方均可能出現(xiàn)相互等待的死鎖局面的問題,TCP 為每一個連接均設(shè)有一個 ** 持續(xù)計時器 ** (persistence timer)。只要 TCP 連接的一方收到對方的零窗口通知,就啟動持續(xù)計時器。若持續(xù)計時器設(shè)置的時間到期,就發(fā)送一個 ** 零窗口探測報文段 ** (攜 1 字節(jié)的數(shù)據(jù)),而對方就在確認(rèn)這個探測報文段時給出當(dāng)前的窗口值。若窗口仍然為 0,則收到該報文段的一方就重設(shè)持續(xù)計時器。若窗口不為0,則發(fā)送方就可以根據(jù)該窗口值繼續(xù)發(fā)送報文。
TCP 報文發(fā)送時機(jī)
應(yīng)用程序?qū)?shù)據(jù)發(fā)送到 TCP 的發(fā)送緩沖區(qū)后,剩下的發(fā)送過程就交給 TCP 來控制了,所以為了盡可能提高傳輸速率,就需要采用不同的發(fā)送機(jī)制來控制 TCP 報文的發(fā)送時機(jī)。
- TCP 維持一個變量,該變量等于最大報文段長度 MSS。只要緩存中存放的數(shù)據(jù)達(dá)到MSS 字節(jié),就組裝成一個 TCP 報文段發(fā)送出去。
- 由發(fā)送方的應(yīng)用進(jìn)程指明要求發(fā)送的報文段長度,即 TCP 支持的推送( push )操作。
- 發(fā)送方設(shè)置一個計時器,當(dāng)發(fā)送方的一個計時器期限到期時,就將已有的緩存數(shù)據(jù)裝入報文段(但長度不能超過 MSS )發(fā)送出去。
*** Nagle 算法 ***
若發(fā)送應(yīng)用進(jìn)程把要發(fā)送的數(shù)據(jù)逐個字節(jié)地送到 TCP 的發(fā)送緩存,則發(fā)送方就把第一個數(shù)據(jù)字節(jié)先發(fā)送出去,把后面到達(dá)的數(shù)據(jù)字節(jié)都緩存起來。當(dāng)發(fā)送方接收對第一個數(shù)據(jù)字符的確認(rèn)后,再把發(fā)送緩存中的所有數(shù)據(jù)組裝成一個報文段再發(fā)送出去,同時繼續(xù)對隨后到達(dá)的數(shù)據(jù)進(jìn)行緩存。只有在收到對前一個報文段的確認(rèn)后才繼續(xù)發(fā)送下一個報文段。當(dāng)數(shù)據(jù)到達(dá)較快而網(wǎng)絡(luò)速率較慢時,用這樣的方法可明顯地減少所用的網(wǎng)絡(luò)帶寬。Nagle 算法還規(guī)定:當(dāng)?shù)竭_(dá)的數(shù)據(jù)已達(dá)到發(fā)送窗口大小的一半或已達(dá)到報文段的最大長度時,就立即發(fā)送一個報文段。
*** 糊涂窗口綜合證 ***
TCP 接收方的緩存已滿,而交互式的應(yīng)用進(jìn)程一次只從接收緩存中讀取 1 字節(jié)(這樣就使接收緩存空間僅騰出 1 字節(jié)),然后向發(fā)送方發(fā)送確認(rèn),并把窗口設(shè)置為 1 個字節(jié)(但發(fā)送的數(shù)據(jù)報為 40 字節(jié)的的話)。接著,發(fā)送方又發(fā)來 1 個字節(jié)的數(shù)據(jù)(發(fā)送方的 IP 數(shù)據(jù)報是 41 字節(jié),40 字節(jié)頭部)。接收方發(fā)回確認(rèn),仍然將窗口設(shè)置為 1 個字節(jié)。這樣,網(wǎng)絡(luò)的效率很低。要解決這個問題,可讓接收方等待一段時間,等到接收緩存有足夠空間容納一個最長的報文段,或等到接收方緩存已有一半空閑的空間時,接收方才發(fā)回確認(rèn)報文,并向發(fā)送方通知當(dāng)前的窗口大小。此外,發(fā)送方也不要發(fā)送太小的報文段,而是把數(shù)據(jù)報積累成足夠大的報文段,或達(dá)到接收方緩存的空間的一半大小再發(fā)送。
上述兩種算法可以配合使用,使得在發(fā)送方不發(fā)送很小的報文段的同時,接收方也不至于在接收緩存還不夠大時就急忙通知發(fā)送方發(fā)送數(shù)據(jù),從而盡可能提高網(wǎng)絡(luò)帶寬利用率和數(shù)據(jù)吞吐量。
滑動窗口協(xié)議與停止等待協(xié)議的區(qū)別
*** 停止等待協(xié)議 ***
發(fā)送方每發(fā)送完一個報文段后就停止發(fā)送,等待接收方的確認(rèn)報文,在收到確認(rèn)報文段后再繼續(xù)發(fā)送數(shù)據(jù)。
*** 連續(xù)ARQ協(xié)議 ***
發(fā)送方維持一個發(fā)送窗口,位于發(fā)送窗口中的數(shù)據(jù)都可以連續(xù)發(fā)送出去,而無需等待對方的確認(rèn),以此提高信道利用率。每收到一個確認(rèn)報文,發(fā)送方就將滑動窗口向前滑動一個分組長度。接收方則一般采用 ** 累計確認(rèn) ** 的方式,即接收方不必對收到的報文段逐個確認(rèn),而是在收到幾個分組后,只對按序到達(dá)的最后一個分組發(fā)送確認(rèn)報文,表明到該分組為止的所有報文均已正確收到。 ** 優(yōu)點(diǎn) ** :實(shí)現(xiàn)簡單,即便確認(rèn)報文丟失也不必重傳; ** 缺點(diǎn) ** :接收方無法向發(fā)送方全面反映自己已經(jīng)接收到的正確報文情況。
滑動窗口協(xié)議與停止等待協(xié)議的區(qū)別:
- 滑動窗口協(xié)議中,允許發(fā)送方發(fā)送多個分組(當(dāng)有多個分組可用時), 而不需等待確認(rèn),但它受限于在流水線中未確認(rèn)的分組數(shù)不能超過某個最大允許數(shù) N。
- 滑動窗口協(xié)議是 TCP 使用的一種控制流量的方法,此協(xié)議能夠加速數(shù)據(jù)的傳輸。 只有在接收窗口向前滑動時(與此同時也發(fā)送了確認(rèn)), 發(fā)送窗口才有可能向前滑動。收發(fā)兩端的窗口按照以上規(guī)律不斷地向前滑動,因此這種協(xié)議稱為滑動窗口協(xié)議。
- 當(dāng)發(fā)送窗口和接收窗口的大小都等于 1 時,就是停止等待協(xié)議。