小村軟體有限公司
第 3 章

序號與重傳 — TCP 如何確認資料已送達

為每一個位元組編號,用 ack 號碼 = 下一個想要的位元組來對答案。區分沒送到時的 2 種發現方式 — 重傳計時器與重複 ACK。

怎麼確認「應該送到了」

如第 1 章所見,IP 不會告訴你它弄丟了東西。即便如此,TCP 仍承諾「一定送達,沒送到就會發現」。機關非常樸素,類似宅配的托運單號碼與簽收

編號(seq)
為送出的每一個位元組編上連續號碼。區段的標頭裡寫的是開頭位元組的編號
回覆簽收(ack)
接收端回覆「下一個想要的位元組編號」。ack = 1501 的意思是「1500 為止毫無空洞地收到了」
沒有回音就重送
一定時間內沒有 ACK 就視為遺失並重傳。不管送達幾次,都能靠編號識破重複

重要的是,編號不是以封包為單位,而是以位元組為單位。對 TCP 而言資料是「位元組的流」,區段(放上封包的單位)只不過是把這條流切成方便大小的斷片。起算的號碼已在前一章的交握中取得共識,所以雙方從一開始就能用同一把尺數位元組。以下的例子中,為了易讀,把起算點設為 1000,第一個資料位元組設為 1001。

連續的位元組序列被編上連續號碼,區段切出其中一段範圍來運送,接收端以 ack 回覆下一個想要的位元組編號的示意圖

seq = 1001 的 500 位元組區段運送位元組 1001〜1500,ACK 指向「下一個想要的」1501。編號的主角不是區段,而是位元組。

ack 號碼 = 下一個想要的位元組編號

讀封包擷取時最大的要害,是 ack 號碼的解讀。它指的不是「收到了哪裡為止」,而是「接下來想從哪裡開始要」。從 seq = 1001 收了 500 位元組,送達的最後一個位元組是 1001 + 500 − 1 = 1500 號。所以回覆的 ack 是 1501。

另一個要害是累積確認這個性質。ACK 只能表達「到這裡為止毫無空洞地連續收到了」。即使中間的 3001〜4000 缺著而 4001〜5000 送達了,能回覆的 ack 仍停在 3001。送達的部分先保管在接收緩衝區,空洞補上的瞬間,ack 會一口氣跳到 5001。這個「保管並重新排好」的動作,正是承諾之 2「按照順序」的實體。

練習 3-1 — 手算 seq 與 ack

讀懂封包擷取的能力,全部以這個計算為地基。請把位元組的範圍寫在紙上確認。

Q1. 送信端以 seq = 1001 的區段送出 500 位元組的資料。接收端收到後回覆的 ack 號碼是多少?

Q2. 接收端已連續收到位元組 3000 為止。此時,跳過中間的 3001〜4000,先送達了 4001〜5000 的區段。接收端回覆的 ack 號碼是多少?

Q3. TCP 的序號不是「以區段(封包)為單位」而是「以位元組為單位」編號,其優點是哪一個?

發現方式 1 — 沉默(重傳計時器)

ACK 沒有回來時,該等多久才可以判斷「遺失了」?太短會用無謂的重傳壓迫網路,太長會讓使用者空等。TCP 每次傳送都持續量測往返時間(RTT:從送出到 ACK 回來的時間),並由其平均與波動動態計算重傳逾時(RTO)。同一棟建築內是數毫秒,跨洲則是數百毫秒 — 尺會配合線路而改變。

RTO 滿期後就重傳缺漏的區段,並把 RTO 加倍再等下一次(指數退避)。ACK 不回來的最有力原因是壅塞,所以越是重送就把間隔拉得越開,避免對壅塞追加打擊的設計。

發現方式 2 — 悲鳴(重複 ACK)與快速重傳

有比等待沉默更快的方法。位元組 8000 為止送達後,8001〜9000 遺失,只有其後續持續送達的話,接收端每次都只能回覆 ack = 8001。從送信端來看,就是相同號碼的 ACK 反覆到達 — 這就是重複 ACK。

重複 ACK 每一封都在說「後續到了,8001 開始的洞卻補不上」。相同的東西到了 3 次,送信端就不再等了。推理出後續有送達 = 路徑活著 = 缺的大概只有 1 個,不等 RTO 就只重傳 seq = 8001 的區段。這就是快速重傳

在封包擷取中找到重傳時,請看它是哪一種重傳。重複 ACK 引起的是輕微的單發遺失,逾時引起的是完全沒有回應的嚴重狀態 — 同樣是「重傳」,解讀卻正好相反。

練習 3-2 — 怎麼發現「沒送到」

TCP 沒有「沒送到」的通知。要從沉默與重複這 2 種間接證據來推理。

Q4. 關於重傳計時器(RTO)的說明,正確的是哪一個?

Q5. 送信端有時會不斷收到相同 ack 號碼的 ACK(重複 ACK)。接收端發生了什麼事?

Q6. 相同的重複 ACK 到達 3 次時,送信端不等逾時就重傳缺漏的區段(快速重傳)。可以不等逾時就送的判斷根據是哪一個?

本章帶走的重點

  • 編號是以位元組為單位。seq = 1001 的 500 位元組運送位元組 1001〜1500
  • ack 號碼 = 下一個想要的位元組編號。而且是累積確認 — 無法越過空洞前進
  • 發現遺失的方式有 2 種:沉默(RTO 滿期、指數退避)悲鳴(重複 ACK 3 次 → 快速重傳)
  • 重複 ACK 引起的重傳是輕症,逾時引起的重傳是重症的訊號

到這裡,「一定送達、按照順序」的機制已經齊全。下一章是承諾之 3 的前半 — 配合對方狀況的滑動視窗。共乘在 ACK 上的「還能再收多少位元組」這個數字將成為主角。