TCP 流量控制 (Flow Control),
用於平衡 傳送端 與 接收端的流量,
避免 高速傳送端 癱瘓了 低速接收端。
目錄
接收緩衝區 (Receiving Buffers)
滿了的信箱,繼續塞信會如何?
— — 爆掉
滿了的胃,不斷地吃會如何?
— — 死掉
信 與 食物的補充,與『消化』速度並不相等!
它們需要『消化』,才能繼續裝新東西,
信箱或胃,這種用來儲存、待消化的空間,
即是 — — 接收緩衝區 (Receiving Buffers) 概念。
同理,維護應用層資料的 — — 傳輸控制協定 (Transmission Control Protocol, TCP) ,
由於 發送者 (Sender) 與 接收者 (Recipient) 傳輸、讀取的速率不相等,
接收端 會將資料暫存在 接收緩衝區 (Receiving Buffers),
並等待 應用層讀取後 (消化),再從 接收緩衝區 中清除。
TCP 每次 發送 與 接收 單位為: TCP 區段 (TCP Segment),
每個區段的大小不盡相同,有可能 數百~數萬 個位元組。
TCP/IP 的網路層 — — IP 協定,不保證資料會照發送順序抵達 接收端,
接收端 可利用表頭中的 序列號 (Sequence Number, SEQ) 欄位 進行排序、消除重複 (eliminate duplicates),
以保證資料接收的正確順序,並以 位元組串流 (byte-stream) 的方式,傳遞給應用層。
接收視窗 (Receive Window)
接收緩衝區 (Receiving Buffers),實際上就是一段記憶體位址,
時常使用 環狀佇列 (circular queue) 資料結構來實作,
使空間有效率的復用,並避免大量資料的搬移。
『環狀』僅為概念上的表示,實際仍為線性資料,
因此更常表示為:
(僅為示意,實際大小通常為數萬個以上之位元組)
- 1、2 ,為應用層已讀取,
並從 接收緩衝區 清除之位元組。 - 3、4、5、6 為已接收 並 確認 (acknowledged) 收到,
應用層尚未讀取 (消化) 之位元組。 - 在 接收視窗 內的 7、8、9、10、11 為等待接收資料的 空的緩衝區,
3、4、5、6、7、8、9、10、11 合計就是 接收緩衝區大小 ! - 超出 接收視窗大小 (Receive Window Size, rwnd) 的部分則無法接收。
接收視窗 (Receive Window),
是 TCP 用來計算 接收緩衝區 的機制,
一般稱 接收視窗大小 (Receive Window Size) 為 — — rwnd,
rwnd = 接收緩衝區大小 – 等待被應用層接收之位元組大小
公式推導 (參考上圖):
盤子 7、8、9、10、11 = 接收緩衝區大小 - (披薩 + 漢堡 + 雞腿 + 啤酒) (咦?) => 5 = 9 - 4
- 當 接收端 收到資料,並回覆 確認 (acknowledgment) 收到,
接收視窗 會 關閉 (Close) (左牆 往右移)。 - 當 接收段 應用層讀取資料 (消化) 時,資料會被清除,
接收視窗 會 開啟 (Open) (右牆 往右移)。
範例
延續上述例子,這時收到了 7、8 位元組,並回覆 確認 (acknowledgment),
接收視窗 關閉 (Close) (左牆 往右移),rwnd = 3
接著,應用層讀取了 3、4、5 位元組,其自 接收緩衝區 中清除,
接收視窗 開啟 (Open) (右牆 往右移),rwnd = 6
再次提醒:
實際上不可能傳輸這麼小的區段,僅為幫助理解用。
發送緩衝區 (Sending Buffers)
發送者 將欲傳送的資料,
置於 發送緩衝區 (Sending Buffers) 並送出。
就像 接收緩衝區 會等到『消化』(應用層接收資料) 後才將資料清除,
發送緩衝區 (Sending Buffers) 送出資料後,
會等到 接收者 回覆: 確認 (acknowledgment) 收到,
才將資料由 發送緩衝區 中清除。
不論是 發送 或 接收緩衝區,
其空間都會被回收,重複利用,
這也是為何,緩衝區 時常以 『環狀』資結來實作。
發送視窗 (Send Window)
- 1、2 ,為已傳送 並 收到接收端 確認 (acknowledgment),
並從 發送緩衝區 清除之位元組。 - 在 發送視窗 內的 3、4、5、6 為已傳送 但 未被確認 (unacknowledged),
待 接收者 回覆確認之位元組。 - 在 發送視窗 內的 7、8、9、10、11 為準備傳送的位元組。
- 超出 發送視窗 外的 12、13、14,為等待置放欲傳送資料的 空的緩衝區,
3、4、5、6、7、8、9、10、11、12、13、14 合計就是 發送緩衝區大小 !
為什麼發送完的資料,要等到接收者回覆確認,
不立即從緩衝區中清除,卡在那拖台錢?
先別說台錢了,你聽過 錯誤控制 (Error Control) 嗎?
TCP 透過 錯誤控制 (Error Control) 機制,
確保了傳輸的可靠性 (reliable),
其中最常見的是: 檢驗和 (checksum)、確認 (acknowledgment)、重送 (retransmission)。
TCP 會為每個連線啟動 一個 逾時重送 (Retransmission Time-out, RTO) 計時器 ⏰,
當時間到期,尚未收到接收端的 確認 (acknowledgment) 回覆,
則視同區段毀損 (遺失、延遲),並 重送 該 區段 (Segment),
這便是為何 發送完的資料,會等到接收者回覆確認後,才從佇列中清除。
接收視窗 vs. 發送視窗
若不看 已清除 及 無法接收的部分,接收緩衝區 有兩種資料空間:
- 已接收 並 確認 (acknowledged) 收到,
應用層尚未讀取 (消化) 之位元組。 - 等待接收資料的 空的緩衝區。
不同於 接收緩衝區,發送緩衝區 有三種資料空間:
- 已傳送 但 未被確認 (unacknowledged),
待 接收者 回覆確認之位元組。 - 等待置放欲傳送資料的 空的緩衝區。
- 準備傳送的位元組。
且不同於 接收緩衝區: 空的緩衝區在 接收視窗 內,
發送緩衝區: 空的緩衝區在 發送視窗 外!
- 當 接收端 收到資料,並回覆 確認 (acknowledgment) 收到,
發送視窗 會 關閉 (Close) (左牆 往右移)。 - 當收到 接收端 的 接收視窗大小 (rwnd),大於 發送視窗大小,
發送視窗 會 開啟 (Open) (右牆 往右移)。
範例
延續上述例子,這時收到了 接收端 確認號 (acknowledgment number): 7 與 接收視窗大小 (rwnd): 5,
(表 3、4、5、6 確認收到,對方還能接收 5 個位元組)
接收視窗 關閉 (Close) (左牆 往右移):
接著,收到了 接收端 確認號 (acknowledgment number): 9 與 接收視窗大小 (rwnd): 6,
(表 7、8 確認收到,對方還能接收 6 個位元組)
接收視窗 先 關閉 (Close) (左牆 往右移),再 開啟 (Open) (右牆 往右移):
TCP 流量控制
(TCP Flow Control)
聰明如你,有沒有覺得奇怪?
為何 接收視窗 可以自行計算視窗大小,
然而 發送視窗 皆需取決於 接收端?
因為,這就是 流量控制 (Flow Control)。
TCP 流量控制 (TCP Flow Control),
用於平衡 傳送端 與 接收端的流量,
避免 高速傳送端 癱瘓了 低速接收端。
也就是透過 回饋 (feedback):
接收端 告知 傳送端,目前能接收多少資料。
接收端 告知 傳送端,目前能接收多少資料。
接收端 告知 傳送端,目前能接收多少資料。
— — 覺得很重要 0.0
就像你要告訴你媽: 「我今天沒很餓,只吃一點點」,
否則媽咪可能會煮 10 盤菜 😂
暫不考慮 壅塞控制 (congestion control):
TCP 的 發送視窗大小,主要由 接收端 來維護,
每次回報確認時,皆會告知傳送端 接收視窗 (rwnd) 大小。
這種 動態調整視窗大小,來實現流量控制的方式,
即是鼎鼎大名的 — — 滑動視窗 (Sliding Window)。
如果滿了的 接收緩衝區,傳送端 繼續傳送? 🤔
— — 接收端 丟棄區段
正常情況:
接收端 可能因為某些因素傳送 rwnd = 0,
傳送端 會停止傳送 (而非收縮 發送視窗),
直到 接收端 送出 != 0 的 rwnd。
儘管 TCP 是可靠的 (reliable) 傳輸協定,
擁有重送 (retransmission) 的機制。
仍應使用 TCP 流量控制 (TCP Flow Control) 改善傳輸效率,並預防資料項目的遺失。
誤解
另外,有個很大的誤會:
傳送端 = 客戶端 接收端 = 伺服端
並非如此!
要知道 TCP 為 全雙工 (Full-Duplex, FDX),
也就是每個端點,在同一時間,資料可雙向的流動,
因此每個端點,各有一個 傳送緩衝區 與 接收緩衝區!
在《TCP 流量控制 (Flow Control)》中有 27 則留言
感謝 Jason 好文~淺顯易懂^^
謝謝您😭
Jason 兄 這麼晚還在寫文章哦…
最近自己也在慢慢整理以前所學跟最近在學 RoR 的心得,以前實在是太懶了,現在記性愈來愈差…
看到你的文章這麼用心,值得學習,不推一下,對不起自己^^
太感動啦 ! 😭
想寫的的東西太多…
然而每天私務忙完都晚上了..
只能壓縮睡眠時間了😂
我會繼續努力的 感謝支持!
推~~感謝大大分享 期待下一篇
優質文章 希望還有更多詳細介紹
謝謝分享,受益良多!
感謝分享,每一篇都有看,收穫很多
感謝大大分享功德無量
感恩感恩 阿彌陀佛
感謝大大~獲益良多~圖片跟文字都解釋的很好很棒~!謝謝你~!
淺顯易懂!感謝大大m(_ _)m
感謝 😇
感謝大大~
不會 😉
倒是您怎這麼晚還在努力 😭
辛苦啦 早點休息囉!
圖例做得很用心,感謝分享
淺顯易懂,圖例精美,受益良多
非常感謝
謝謝鼓勵 😋
非常優質的文章!
感謝 😃
感謝!受益良多
目前看到最容易理解sliding window的文章 🙂
謝謝!很高興能幫到您 😆
感謝~~~~2020還在看
分析的讓人易懂
感謝分享!!
寫的很棒,另外憑證過期了,希望作者能更新~