序號與重傳 — TCP 如何確認資料已送達
為每一個位元組編號,用 ack 號碼 = 下一個想要的位元組來對答案。區分沒送到時的 2 種發現方式 — 重傳計時器與重複 ACK。
怎麼確認「應該送到了」
如第 1 章所見,IP 不會告訴你它弄丟了東西。即便如此,TCP 仍承諾「一定送達,沒送到就會發現」。機關非常樸素,類似宅配的托運單號碼與簽收。
重要的是,編號不是以封包為單位,而是以位元組為單位。對 TCP 而言資料是「位元組的流」,區段(放上封包的單位)只不過是把這條流切成方便大小的斷片。起算的號碼已在前一章的交握中取得共識,所以雙方從一開始就能用同一把尺數位元組。以下的例子中,為了易讀,把起算點設為 1000,第一個資料位元組設為 1001。
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 號碼是多少?
這個區段運送的是位元組 1001〜1500 的 500 位元組(1001 + 500 − 1 = 1500)。ack 號碼是「下一個想要的位元組編號」,所以回覆 1500 的下一個,也就是 1501。不是「收到的最後一個編號」而是「下一個想要的編號」— 把這個差 1 內化,是讀懂封包擷取的第一步。
Q2. 接收端已連續收到位元組 3000 為止。此時,跳過中間的 3001〜4000,先送達了 4001〜5000 的區段。接收端回覆的 ack 號碼是多少?
TCP 的 ACK 是累積確認。它只能表達「到這裡為止毫無空洞地連續收到了」,所以就算 4001〜5000 已在手邊,也不能越過缺漏的 3001 往前。送達的 4001〜5000 會保管在接收緩衝區,並回覆 ack = 3001。這個「重複回覆相同 ack」的動作,是後半重複 ACK 的伏筆。
Q3. TCP 的序號不是「以區段(封包)為單位」而是「以位元組為單位」編號,其優點是哪一個?
TCP 運送的是位元組的流,而不是封包的序列。重傳時可能把多個區段重新整併、也可能因路徑的狀況被切割,區段的切點是會變的;但只要用位元組為單位編號,不管怎麼重新切,「送達到哪裡」都能唯一確定。這個「主角不是區段而是位元組」的觀點,也直通第 6 章的 framing 問題。
發現方式 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)的說明,正確的是哪一個?
RTO 是「等了這麼久還沒有 ACK 就視為遺失」的門檻值,由 RTT 的量測值與波動動態決定。近距離就短,遠距離就長。重傳之後若仍沒有 ACK,就把等待時間成倍延長(指數退避),避免對已壅塞的網路追加打擊。接收端無法通知「沒有收到」— 因為沒送到的東西,沒有人會發現它沒送到。
Q5. 送信端有時會不斷收到相同 ack 號碼的 ACK(重複 ACK)。接收端發生了什麼事?
這是累積確認的必然結果。收到位元組 8000 為止、8001〜9000 缺漏,而後續(9001〜、10001〜…)持續送達時,接收端每次都只能回覆 ack = 8001。也就是說,重複 ACK 是接收端發出的「後面的都到了,只有這裡缺著」的悲鳴。緩衝區滿是以視窗 0 的通告(第 4 章)來傳達的,是另一回事。
Q6. 相同的重複 ACK 到達 3 次時,送信端不等逾時就重傳缺漏的區段(快速重傳)。可以不等逾時就送的判斷根據是哪一個?
重複 ACK 是每有一個後續區段送達就會產生的。也就是說到了 3 次,至少有 3 個後續平安送達 — 路徑活著,缺的大概只有 1 個。那麼等待 RTO 滿期(數百毫秒〜秒級的沉默)就是浪費。逾時重傳是從沉默做的推理,快速重傳是從送達證據做的推理。故障記錄中發生的是哪一種重傳,會改變對網路狀態的解讀(第 5 章、第 7 章)。
本章帶走的重點
- 編號是以位元組為單位。seq = 1001 的 500 位元組運送位元組 1001〜1500
- ack 號碼 = 下一個想要的位元組編號。而且是累積確認 — 無法越過空洞前進
- 發現遺失的方式有 2 種:沉默(RTO 滿期、指數退避)與悲鳴(重複 ACK 3 次 → 快速重傳)
- 重複 ACK 引起的重傳是輕症,逾時引起的重傳是重症的訊號
到這裡,「一定送達、按照順序」的機制已經齊全。下一章是承諾之 3 的前半 — 配合對方狀況的滑動視窗。共乘在 ACK 上的「還能再收多少位元組」這個數字將成為主角。