National Central University
Uedu Main Site
Explore Uedu
Student Console
Register as Member/Login
Research Informed Consent Center
Survey Center
Educational Big Data Challenge
Claim or create a course
Try an AI Scenario Task
Support & Messages
Uptime Data

UeduGPTs

--

Jupyters

3

Local AI

--

Uedu Code

--

中央大學 AQI 80 24°C PM2.5 21
AI Reply Desktop Notifications

Show a desktop notification when the AI TA finishes replying

Chat Message Notifications

Notify me when classmates post messages in the forum

Sound notification

Play an alert sound whenever there is a new notification

Unit 17

TCP(二):可靠傳輸與壅塞控制

重傳、滑動視窗、流量控制與壅塞控制
Interaction 25 minute(s)

Learning Objectives

  • 說明 TCP 怎麼用確認、逾時重傳與快速重傳補回遺失的資料
  • 比較停等與滑動視窗,用「視窗÷來回時間」估計傳輸量的上限
  • 說明接收視窗(流量控制)保護的是接收端,壅塞視窗(壅塞控制)保護的是網路
  • 描述慢啟動、壅塞避免,以及兩種遺失(重複確認、逾時)之後 cwnd 怎麼變
  • 依應用的需求判斷該用 TCP 還是 UDP

可靠,而且不能太慢、不能太快

上一課看到 TCP 用序號與確認號記錄「誰收到了什麼」。這一課回答兩個問題:

  1. 封包遺失了怎麼辦? IP 不保證送達,路由器的佇列滿了就會丟封包。TCP 要發現遺失,並且重送。
  2. 一次可以送多少? 送太少,線路閒著,很慢;送太多,接收端來不及處理,或者把網路塞爆,反而丟更多封包。
機制 解決什麼 由誰決定
確認與重傳 遺失、重複、亂序 傳送端與接收端合作
滑動視窗 不必每送一個就停下來等 傳送端
流量控制(接收視窗 rwnd) 別送得比接收端讀得快 接收端在每個 ACK 裡告訴傳送端
壅塞控制(壅塞視窗 cwnd) 別送得比網路承受得了的快 傳送端依遺失的訊號自己推估

逾時重傳與快速重傳

傳送端每送出資料,就啟動一個重傳計時器(RTO)。在時間內等到確認就取消;時間到了還沒確認,就重送最早那個沒被確認的區段。

RTO 多長才對?太短會把只是比較慢的封包當成遺失,太長又讓遺失後空等。TCP 持續量測來回時間(RTT),依 RFC 6298 計算 RTO: 建議的初始值是 1 秒,每逾時一次就加倍,收到新的確認後再依量到的 RTT 重新計算。

等逾時太慢了,所以 TCP 還有另一個訊號:重複確認(duplicate ACK)。確認號是累積的,假設 1001 遺失、後面 1101、1201、1301 都到了:

接收端收到 回覆的確認號 傳送端看到
1101~1200 1001(還缺 1001) 第 1 個重複確認
1201~1300 1001 第 2 個
1301~1400 1001 第 3 個:幾乎可以確定 1001 遺失了

依 RFC 5681,傳送端收到 3 個重複確認就不等逾時,立刻重送,這叫快速重傳(fast retransmit)。 接收端先把後面亂序到的區段暫存起來,缺的那段補到之後,確認號一次跳到 1401。

只有一兩個重複確認時不重送,因為封包也可能只是走了不同的路、晚一點到(亂序)。 另外,重複的資料(例如確認遺失、傳送端重送了對方其實已經收到的區段)靠序號就能認出來,接收端丟掉並再確認一次。

從停等到滑動視窗

最簡單的做法是停等:送一個區段,等到確認再送下一個。每個區段都要花一個 RTT,線路大部分時間在空等。

滑動視窗允許同時有好幾個區段「已送出、還沒確認」。視窗大小就是這個上限;最早的區段被確認後,視窗往前滑,就可以再送新的:

序號 →   [已確認] [ 已送出、等確認 ][ 可以送 ][ 還不能送 ]
                  ^最早未確認                ^視窗右緣
                  |←───────── 視窗大小 ─────→|

每個 RTT 最多送出一個視窗的資料,所以:

傳輸量上限 ≈ 視窗大小 ÷ RTT
例:視窗 65,535 位元組、RTT 10 毫秒 → 65,535 ÷ 0.01 = 6,553,500 位元組/秒 ≈ 52.4 Mbit/s

TCP 標頭的視窗欄位只有 16 位元(最大 65,535),在高速、長距離的網路上不夠用,所以現代系統會用「視窗縮放」選項把它放大。

下面的模擬器裡,連線已經建立,用戶端要送 6 個 100 位元組的區段給伺服器。先比較視窗 1(停等)與視窗 4 的完成時間, 再讓區段遺失,看快速重傳和逾時重傳的差別。

互動練習:滑動視窗、重傳與流量控制

調整「傳送視窗」後按送出。時序圖左邊是用戶端、右邊是伺服器,伺服器的每個 ACK 都標出確認號與接收視窗 win; 遺失的區段畫成中途斷掉的虛線,重送的區段是金色。完成時間會顯示在說明列(示意值)。

流量控制:接收視窗

接收端的作業系統先把收到的資料放進接收緩衝區,等應用程式呼叫 recv() 讀走。 如果應用程式忙著做別的事、讀得很慢,緩衝區會滿,再送來的資料只能丟掉。

所以接收端在每個 ACK 的視窗欄位寫上「我的緩衝區還剩多少位元組」,這叫接收視窗(rwnd)。傳送端保證「已送出、未確認」的資料不超過它:

剛才的模擬 伺服器回的 win 傳送端
程式正常讀取 一直是 400 照傳送視窗送
暫停讀取,收了 1 個區段 300 還能再送 300
收了 4 個區段 0(零視窗) 停下來,定期送視窗探測問「打開了沒」
程式讀走資料 400(視窗更新) 繼續送

視窗探測是必要的:如果那個「視窗打開了」的 ACK 剛好遺失,兩邊會永遠互相等待。(實際的探測會帶 1 個位元組的資料,模擬器簡化成不帶資料。)

流量控制只照顧接收端。即使接收端很快,中間的網路也可能塞住,那是下一節壅塞控制的工作。

小測驗:重傳與視窗

1.

傳送端依序送出 seq=1001、1101、1201、1301,各 100 位元組;1101 那段遺失了,其他都到。接收端收到 1201 與 1301 時,回覆的確認號是?

2.

為什麼快速重傳要等到 3 個重複確認,而不是 1 個?

3.

視窗大小固定 65,535 位元組,RTT 從 10 毫秒變成 100 毫秒(例如連到國外)。傳輸量上限會怎樣?

4.

伺服器回的 ACK 裡 win=0,代表什麼?

第 1 次作答

壅塞控制:cwnd、慢啟動與減半

網路上同時有很多連線共用路由器。如果每條連線都盡量送,路由器的佇列滿了開始丟封包,大家都重送,網路更塞, 這叫壅塞。傳送端看不到網路裡面,只能從遺失推測「送太快了」,自己控制一個壅塞視窗(cwnd):

實際一次可以送出、還沒確認的量 = min(cwnd, rwnd)

RFC 5681 規定的基本做法(下面以「區段」為單位、以一個 RTT 為一輪來描述):

階段 什麼時候 cwnd 怎麼變
慢啟動(slow start) cwnd 小於門檻 ssthresh 每收到一個確認加 1 個區段,所以每輪約加倍:1、2、4、8…
壅塞避免(congestion avoidance) cwnd 達到門檻之後 每輪只加約 1 個區段,小心試探
收到 3 個重複確認 有遺失,但後面的封包還到得了,網路只是有點塞 門檻設成目前送出量的一半;快速重傳後 cwnd 從門檻繼續(只減半)
逾時 連後續的確認都沒有,情況比較嚴重 門檻設成一半,cwnd 回到 1 個區段,重新慢啟動

「慢啟動」其實成長得很快,名字是相對於「一開始就送滿整個視窗」而言。初始的 cwnd 也不一定是 1:RFC 5681 依區段大小允許 2~4 個區段,實際系統常用更大的值。

「沒有遺失就慢慢加,遺失就砍一半」叫做加法增加、乘法減少(AIMD),讓共用同一條瓶頸線路的連線大致公平地分享頻寬。 上面描述的是 Reno 一類的做法。現在 Linux、Windows 與 Apple 的系統預設用 CUBIC(RFC 9438),遺失後一樣乘法減少,但用三次函數決定增長的速度; 還有其他演算法依量到的頻寬與延遲調整。下面的模擬器用簡化的 Reno 規則。

互動練習:畫出 cwnd 的鋸齒

每按一次「下一輪」代表過了一個 RTT。藍線是 cwnd,金色虛線是門檻 ssthresh,灰色虛線是接收視窗 rwnd。 用兩個「遺失」按鈕決定這一輪發生哪一種遺失,下方表格列出每一輪的數字。

TCP 還是 UDP

兩課看下來,可以用應用的需求來選:

需求 選擇 例子
每個位元組都要完整、依序送達 TCP 網頁、檔案下載、電子郵件、SSH、資料庫連線
即時性比完整重要,晚到不如不到 UDP 語音通話、視訊會議、直播、線上遊戲
一問一答、很短,失敗了再問就好 UDP DNS、NTP 校時
要廣播或群播給很多台 UDP(TCP 只能一對一) DHCP、區域網路裡的裝置探索
想要可靠,又不想被 TCP 的設計綁住 在 UDP 上自己做 HTTP/3 用的 QUIC 在 UDP 上自己實作確認、重傳與壅塞控制

用 TCP 時,重傳與壅塞控制都由作業系統處理,程式只看到可靠的位元組流;用 UDP 時,這些事要不要做、怎麼做,都由應用程式自己決定。

小測驗:壅塞控制與選擇協定

1.

接收視窗 rwnd 與壅塞視窗 cwnd,各自保護誰?

2.

cwnd 從 1 個區段開始慢啟動,門檻 64,一路沒有遺失。4 輪之後 cwnd 是多少?

3.

為什麼「逾時」時 cwnd 降得比「3 個重複確認」更多?

4.

下列哪一個應用最適合用 TCP?

第 1 次作答

重點整理

  • 遺失靠兩種方法發現:逾時(RTO 依 RTT 計算、逾時後加倍)與 3 個重複確認(快速重傳,不用等逾時)。
  • 滑動視窗讓多個區段同時在路上,傳輸量上限約為視窗÷RTT;確認是累積的,遺失一個 ACK 通常不用重送。
  • 流量控制:接收端在 ACK 裡告知接收視窗 rwnd;零視窗時傳送端停下並送探測。
  • 壅塞控制:傳送端維護 cwnd,實際可送=min(cwnd, rwnd);慢啟動每輪加倍、壅塞避免每輪加 1;重複確認時減半,逾時時回到 1。
  • 要完整依序用 TCP;重即時、一問一答或要廣播用 UDP,可靠性需要時由應用程式自己做。

傳輸層到這裡結束。下一課往上到應用層,深入看每次連網的第一步:DNS 怎麼把名稱變成位址。

這一課完成了!
Next lesson:DNS 深入
你目前沒有登入,學習進度只存在這個瀏覽器。 Login 後,進度會跟著帳號,換電腦也看得到。