TCP/IP

TCP 流量控制 (Flow Control)

TCP 流量控制 (Flow Control)
用於平衡 傳送端 與 接收端的流量,
避免 高速傳送端 癱瘓了 低速接收端。
 


 

接收緩衝區 (Receiving Buffers)

滿了的信箱,繼續塞信會如何?
— — 爆掉

 
 
滿了的胃,不斷地吃會如何?
— — 死掉

 
 
信 與 食物的補充,與『消化』速度並不相等!
它們需要『消化』,才能繼續裝新東西,
信箱或胃,這種用來儲存、待消化的空間,
即是 — — 接收緩衝區 (Receiving Buffers) 概念。
 
同理,維護應用層資料的 — — 傳輸控制協定 (Transmission Control Protocol, TCP)
由於 發送者 (Sender) 與 接收者 (Recipient) 傳輸、讀取的速率不相等,
接收端 會將資料暫存在 接收緩衝區 (Receiving Buffers)
並等待 應用層讀取後 (消化),再從 接收緩衝區 中清除。
 
DoD-Model
 
TCP 每次 發送 與 接收 單位為: TCP 區段 (TCP Segment)
每個區段的大小不盡相同,有可能 數百~數萬 個位元組。
encapsulation
 
TCP/IP 的網路層 — — IP 協定,不保證資料會照發送順序抵達 接收端,
接收端 可利用表頭中的 序列號 (Sequence Number, SEQ) 欄位 進行排序消除重複 (eliminate duplicates)
以保證資料接收的正確順序,並以 位元組串流 (byte-stream) 的方式,傳遞給應用層。
 
 

接收視窗 (Receive Window)

接收緩衝區 (Receiving Buffers),實際上就是一段記憶體位址,
時常使用 環狀佇列 (circular queue) 資料結構來實作,
使空間有效率的復用,並避免大量資料的搬移。

 
『環狀』僅為概念上的表示,實際仍為線性資料,
因此更常表示為:
Receive-Window
(僅為示意,實際大小通常為數萬個以上之位元組)
 

  • 1、2 ,為應用層已讀取,
    並從 接收緩衝區 清除之位元組。
  • 3456 為已接收 並 確認 (acknowledged) 收到,
    應用層尚未讀取 (消化) 之位元組。
  • 在 接收視窗 內的 7891011 為等待接收資料的 空的緩衝區,
    34567891011 合計就是 接收緩衝區大小 !
  • 超出 接收視窗大小 (Receive Window Size, rwnd) 的部分則無法接收。


 
接收視窗 (Receive Window)
是 TCP 用來計算 接收緩衝區 的機制,
一般稱 接收視窗大小 (Receive Window Size) 為 — — rwnd

rwnd = 接收緩衝區大小 – 等待被應用層接收之位元組大小

 
公式推導 (參考上圖):

盤子 7891011 = 接收緩衝區大小 - (披薩 + 漢堡 + 雞腿 + 啤酒)  (咦?)
=> 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),
    並從 發送緩衝區 清除之位元組。
  • 在 發送視窗 內的 3456 為已傳送 但 未被確認 (unacknowledged)
    待 接收者 回覆確認之位元組。
  • 在 發送視窗 內的 7891011 為準備傳送的位元組。
  • 超出 發送視窗 外的 121314,為等待置放欲傳送資料的 空的緩衝區,
    34567891011121314 合計就是 發送緩衝區大小 !

 
為什麼發送完的資料,要等到接收者回覆確認,
不立即從緩衝區中清除,卡在那拖台錢?

先別說台錢了,你聽過 錯誤控制 (Error Control) 嗎?

 
TCP 透過 錯誤控制 (Error Control) 機制,
確保了傳輸的可靠性 (reliable),
其中最常見的是: 檢驗和 (checksum)、確認 (acknowledgment)、重送 (retransmission)。
 
TCP 會為每個連線啟動 一個 逾時重送 (Retransmission Time-out, RTO) 計時器 ⏰,
當時間到期,尚未收到接收端的 確認 (acknowledgment) 回覆,
則視同區段毀損 (遺失、延遲),並 重送 該 區段 (Segment),
這便是為何 發送完的資料,會等到接收者回覆確認後,才從佇列中清除。
 
 

接收視窗 vs. 發送視窗

若不看 已清除 及 無法接收的部分,接收緩衝區 有兩種資料空間:

  1. 已接收 並 確認 (acknowledged) 收到,
    應用層尚未讀取 (消化) 之位元組。
  2. 等待接收資料的 空的緩衝區。

 
不同於 接收緩衝區,發送緩衝區 有三種資料空間:

  1. 已傳送 但 未被確認 (unacknowledged)
    待 接收者 回覆確認之位元組。
  2. 等待置放欲傳送資料的 空的緩衝區。
  3. 準備傳送的位元組。

 
且不同於 接收緩衝區: 空的緩衝區在 接收視窗 內,
發送緩衝區: 空的緩衝區在 發送視窗 外!
 

  • 當 接收端 收到資料,並回覆 確認 (acknowledgment) 收到,
    發送視窗 會 關閉 (Close) (左牆 往右移)。
  • 當收到 接收端 的 接收視窗大小 (rwnd),大於 發送視窗大小,
    發送視窗 會 開啟 (Open) (右牆 往右移)。

 
 

範例

延續上述例子,這時收到了 接收端 確認號 (acknowledgment number): 7接收視窗大小 (rwnd): 5
(表 3456 確認收到,對方還能接收 5 個位元組)
接收視窗 關閉 (Close) (左牆 往右移):

 


 
接著,收到了 接收端 確認號 (acknowledgment number): 9接收視窗大小 (rwnd): 6
(表 78 確認收到,對方還能接收 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),
也就是每個端點,在同一時間,資料可雙向的流動,
因此每個端點,各有一個 傳送緩衝區 與 接收緩衝區!
Right and left arrow
 
 

作者: 鄭中勝

喜愛音樂,但不知為何總在打程式 ?
期許能重新審視、整理自身所學,幫助有需要的人。

在《TCP 流量控制 (Flow Control)》中有 23 則留言

      1. Jason 兄 這麼晚還在寫文章哦…
        最近自己也在慢慢整理以前所學跟最近在學 RoR 的心得,以前實在是太懶了,現在記性愈來愈差…
        看到你的文章這麼用心,值得學習,不推一下,對不起自己^^

        1. 太感動啦 ! 😭
          想寫的的東西太多…
          然而每天私務忙完都晚上了..
          只能壓縮睡眠時間了😂
          我會繼續努力的 感謝支持!

發表迴響