TCP/IP

TCP 錯誤控制 (Error Control)

TCP 錯誤控制 (Error Control) ,確保了傳輸的可靠性 (reliable),
其中最常見的是: 檢驗和 (checksum)、確認 (Acknowledgment)、重送 (retransmission)。
 


 

可靠性 (Reliability)

暸解 TCP 錯誤控制 (Error Control) 前, 得先知道何謂 — 錯誤 (Error)。
All men's mistakes
 
錯誤 (Error),是指那些傳遞於網際網路通訊系統中,
毀損 (damaged)遺失 (lost)延遲 (delayed)
重複 (duplicated)亂序 (out of order)區段 (Segment)
 
錯誤控制 (Error Control),並非指 TCP 不會有錯誤,
而是當錯誤發生時,偵測 並 修正 這些問題,
藉此讓 TCP 擁有了 可靠性 (Reliability)
 
關鍵在於:

為每個送出的資料之位元組 (octet),分配 序列號 (Sequence Number)

 

 
TCP/IP 的網路層 — — IP 協定,不保證資料會依發送順序抵達 接收端,
接收端 可利用表頭中的 序列號 (Sequence Number, SEQ) 欄位 進行排序、消除重複
以保證資料接收的正確順序,並以 位元組串流 (byte-stream) 的方式,傳遞給應用層。
 
TCP 接收端 需透過 確認號 (Acknowledgment Number)
回應 傳送端 資料是否已正確收到,
若超出限定時間,傳送端 仍未收到 接收端 的 確認號,
則視為 區段遺失 (毀損、延遲),並重送該區段。

 
此外,TCP 使用 檢驗和 (Checksum) 的計算機制,檢查區段是否毀損,
傳送端 將每個送出的區段,進行 檢驗和計算,並將結果置於 TCP 表頭 的 Checksum 欄位中,
接收端 會進行相同的計算,若與表頭中的 Checksum 值不同,則視為毀損 (遺失、延遲),並丟棄該區段。
 


 

確認 (Acknowledgment)

確認 (Acknowledgment),又稱 承認、回報、回應,是一種偵錯機制。
 
主要是透過:
確認號 (Acknowledgment Number)ACK 兩個 TCP 表頭欄位。
前者,欄位大小為 32 bits,因此其 數值範圍 為 0 ~ 232 – 1;
後者,欄位大小為 1 bit,是控制位元 (Control Bits) [註1] 其一,
意指: 使「確認號欄位」有效 (Acknowledgment field significant)。
 

TCP 表頭格式
 
確認號 (Acknowledgment Number) 用於:

  1. 告知 傳送端,下個預期接收的 序列號 (Sequence Number)
  2. 告知 傳送端,小於 此值的 資料位元組,皆已正確接收。
    (這種確認方式稱為: 『累計式確認 (Comulative ACK)』)

也就是 (若傳輸正確):

確認號 為 所收到區段的 最後一個 位元組之 序號 + 1

 
例如:

 
代表 Server:

  1. 下次期望收到 序列號 301 之區段
  2. 小於 301 之區段,皆已正確接收。

(這裡用 101 ~ 200 這樣的序列號表示法,
僅為方便示意,實際上序列號只有一個值)
 

一旦連線建立,不管是 Client 還是 Server,
所有送出的 區段,都需包含 確認號,並設置 ACK

 
上述 Client-Server 的例子中,
可看出一個重要的事實:

TCP 區段,並非 一個傳送 對應 一個接收

 
許多人將一些應用程序:「一個請求 一個回應」的習慣,
加附在 TCP,進而產生誤解。
 
[註1]:
控制位元 (Control Bits),又稱旗標,大小皆為 1 個 bit (0 或 1),
0 表關閉 (未設置 Not Set),1 表啟用 (設置 Set),
許多實作的 控制位元 為 8 個 (剩下 2 個在 保留欄位)。
 
 
[註2]:
許多人為求方便,表示上會將 確認號 與 ACK 視為相等 (縮寫),
圖形 若只寫 ACK,通常代表 ACK 控制位元,
若後方加上某個數值,指的是 確認號。

 
 

延遲確認 (Delayed ACK)

TCP 接收端,可能不會立即發送 確認 (ACK),
而是等待看看,是否有其他訊息,並將多個回應結合為一,
如此便能減少網路中的封包數量,降低兩端主機的負載、傳輸量,
稱為 — — 延遲確認 (Delayed ACK)
 

若 接收端 收到的區段順序正確,
且先前的區段皆已回應 + 已沒有資料要傳送,
應使用 延遲確認,直到 有新的區段抵達 超過『盡量』的時限

 

新的區段抵達:

接收端 在任何時間下,
不該有兩個以上「正確順序的區段 未被回應」。
 

接收端 使用 延遲確認 (Delayed ACK),等待看看,是否有其他訊息:

有!接收到了新的區段 (SEQ: 9400~9486),且先前的區段尚未回應 (SEQ: 9300~9399),

雖 尚未逾時,仍應立即送回 一個 確認 (ACK) 區段。

 
 

超過 延遲確認 時限:

盡量』 的延遲回應時間,
通常是 100~200 毫秒 (ms) ,至多為 500 毫秒 (ms),因設定而異,
然而,若在不當時機,使用 延遲確認 只會弊大於利,
TCP 傻瓜視窗症候群 (Silly Window Syndrome, SWS) 一文有更多介紹。
 
Delayed-ACK
接收端 使用 延遲確認 (Delayed ACK),等待看看,是否有其他訊息:

沒有,接收端 超出 延遲確認 時限後,送回 確認 (ACK) 區段。

 


 

重送 (Retransmission)

一旦 連線建立,TCP 以 區段 (segment) 的交換來傳遞資料。
 
如開頭所述,
接收端 可能因「檢驗和測試失敗」,認定區段毀損並丟棄,
或 網路壅塞… 等因素,而遺失區段,
TCP 使用 重送 (Retransmission) 機制,確保每個 區段 的傳遞。
 
大部分的 TCP 實作,將區段的 —
毀損 (damaged)遺失 (lost)延遲 (delayed) 視為相同情況,
差別在於 毀損的區段 由 接收端 丟棄,而 遺失的區段 由 網路的某處丟棄。
 
常見的重送機制有兩種:

  • 逾時重送 (Retransmission Timeout, RTO)
  • 快速重送 (Fast Retransmit)

 
事實上:

TCP 傳輸錯誤的比例很低,
當區段遺失時,TCP 假設遺失是 壅塞 所造成。

 
因此,重送機制,常作為 偵測壅塞 的具體方式。
 


 

逾時重送 (Retransmission Timeout, RTO)

TCP 流量控制 (Flow Control) 中提到:

TCP 會為每個連線啟動 一個 逾時重送 (Retransmission Timeout, RTO) 計時器 ⏰,
當時間到期,尚未收到接收端的 確認 (acknowledgment) 回覆,
則視同區段毀損 (遺失、延遲),並 重送 該 區段 (Segment),
這便是為何 發送完的資料,會等到接收者回覆確認後,才從佇列中清除。

 
逾時重送 (Retransmission Timeout, RTO)
在大部分文章 (獻) 都直稱 重送 (Retransmission),
本篇為直覺地 與 快速重送 做出區隔,故命之。
 
由於 TCP 連線 與 網際網路 的多變性,
TCP 會根據 往返時間 (Round Trip Time, RTT)
動態調整 逾時重送 (Retransmission Timeout, RTO) 時間,
 
往返時間 (Round Trip Time, RTT)
是測量 送出區段,到接收 確認 (ACK) 的時間而得,
RTO 簡易的計算方式,可以參考 RFC 793RFC 1122RFC 6298
 
 

遺失 (Lost)

以 遺失資料區段 為例:


 
Server 送來兩個區段,第一個區段遺失了 (SEQ: 101~200),
Client 只知道收到一個 亂序 的區段 (SEQ: 201~300),
Client 仍預期接收 序列號 101 的區段。
並且:

TCP 應保證資料的順序,
在 空缺的部分 補齊之前,
接收端 不應將空缺之後的資料,傳遞給應用層。

 
當超出 逾時重送 (Retransmission Timeout, RTO) 計時器 ⏰ 時間,
Server 仍未收到第一個區段的 確認 (ACK) 回覆,
因此,視區段毀損 (遺失、延遲),並 重送 該 區段。
 
注意:

確認 (ACK) 是 累計式的,
儘管 第二個區段 (SEQ: 201~300) 傳輸正確,
第三個區段 不能回應 (ACK: 301),因這樣代表 序列號 小於 301 之區段 傳輸正確。

 

以 遺失ACK區段 為例:


 
Server 送來兩個區段,
Client 送回的 ACK 區段 卻遺失了。
 
當超出 逾時重送 (Retransmission Timeout, RTO) 計時器 ⏰ 時間,
Server 仍未收到 第一/二 個區段的 確認 (ACK) 回覆,
因此,視區段毀損 (遺失、延遲),並 重送 該 區段 (Segment)。
 
Client 會 丟棄 接收到的 重複區段,
並回應 預期接收 的序列號 (ACK)。
 
 

以 遺失ACK區段 為例 (二):


 
Server 送來兩個區段,
Client 送回的 ACK 區段 卻遺失了。
 
這時 Server 仍持續送出區段 (SEQ: 301 ~ 400),且尚未超過 RTO 時限,
Client 回覆 新的 ACK 區段 (甚至未察覺 上個 ACK 區段遺失),
因為是 累計式確認 (Comulative ACK),連帶修正了 「遺失ACK區段」 問題。
 


 

快速重送 (Fast Retransmit)

快速重送 (Fast Retransmit),是另一重送機制,
並非取代 逾時重送,而是結合 並加大 RTO 逾時時間,
讓遺失的區段不需等到 重送計時器 (retransmission timer) 逾時才重送,增加了傳輸效率。
 
 

接收端

某區段遺失,代表後續接收的區段 順序錯誤
因此,不應 使用 延遲確認 (Delayed ACK),
而是 立即確認 (immediate ACK)

 
目的是為了讓 傳送端 知道:

  • 接收到的是 亂序 (out of order) 的區段
  • 預期接收的序列號

 
 

傳送端:

當 接收到 3 個 重複的確認 (duplicate ACK)
則立即重送該區段,而非等到重送計時器逾時。

 
傳送端一開始並不清楚 「重複的確認」的原因 (這可能由多種網路問題),
若收到 1 ~ 2 個重複確認,傳送端 會假設 是網路對區段的重新排序複製 所引起,
而收到 3 個 或 更多的 重複確認,則明顯地指示 區段已遺失
於是 TCP 立即重送 「似乎是」遺失的區段,而非等到計時器逾時。
 
 

範例:


 
原始的 ACK,再加上 3 個重複的 ACK,
合計共有 4 個 相同的 確認號 (acknowledgment number),
區段重送之後,計時器會重新啟動。
 
 


 

選擇式確認
(Selective Acknowledgment, SACK)

 
累計式確認 (Comulative ACK) 的缺點顯而易見,其提供的訊息相當有限:

TCP 傳送端 在每個 往返時間 (RTT),只能知道 單個遺失的封包。

 
因此,當有多個區段的遺失,將為 TCP 帶來災難性的影響,
選擇式確認 (SACK)即是解決 「多個丟棄區段」 時的策略。
 
許多 TCP 實作,使用 選擇式確認 (Selective Acknowledgment, SACK) 來加速傳輸效率,
SACK 並非取代 ACK,而是附加 亂序、重複 的資訊,到 TCP 表頭中的 選項 (Options) 欄位,
使 傳送端 能直接重送遺失的區段。
 
而不使用 SACK 的 TCP,通常使用 部分式確認 (Partial Acknowledgment) 來觸發重送。
 

 
 

允許 SACK 選項
(SACK-permitted Option)

TCP 在建立連線時,可告知對方 允許使用 SACK,
方法很簡單,在 選項表頭欄位 加入 允許 SACK 選項 (04 02):

 
意指:

選項種類 (tcp.option_kind) 為 4 (SACK-permitted),

長度 (tcp.option_len) 為 2 (選項共佔 2 位元組)。

Options-Format
 
 

範例:


 
資料傳輸階段,則不允許使用「允許 SACK 選項」 (SACK-permitted Option)。
 
 

SACK 選項
(SACK Option)

若 TCP 雙方建立連線時,皆送出 SACK-permitted Option (允許使用 SACK),
即可使用 SACK Option (SACK 選項) 附加 亂序、重複 的資訊。
 

其選項種類 為 5 (SACK),

長度 為 需計算的變量 (8*n + 2)。
(左右邊界 合計 8 位元組,選項種類、長度欄位 合計 2 位元組)

 
緊接著:

第一個 亂序/重複 區塊的 開始序列號 -- -- 左邊界 (Left Edge of 1st Block),

第一個 亂序/重複 區塊的 結束序列號 -- -- 右邊界 (Right Edge of 1st Block),
...
...
第n個 亂序/重複 區塊的 結束序列號 -- -- 右邊界 (Right Edge of nth Block)。


 
TCP 選項 至多為 40 位元組,
因此一個 SACK 選項,最多能包含 4 個區塊 (8*4 + 2 = 36)。
 
 

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

在《TCP 錯誤控制 (Error Control)》中有 3 則留言

發表迴響