導入 — TCP 承諾了什麼
從只有 IP 的世界會不送達、亂序、重複的前提出發,掌握 TCP 的 3 項承諾與 UDP 的分工,以及連接埠號與 socket 的角色。
過不了「已逾時」這一關
找到了連線逾時的記錄。重試之後就好了。但「為什麼」始終不明 — TCP 的故障調查,多數人都停在這裡。因為就算打開封包擷取,也讀不懂 seq、ack、win 這一排數字在說什麼。
學會閱讀的捷徑,不是把 TCP 的功能背起來,而是先掌握 TCP 站在什麼樣的地基上、想要承諾什麼。出發點是位於 TCP 之下的 IP 的性質。IP 會把封包(資料的小包裹)運送到目的主機,但這個遞送是「盡力而為(best effort)」— 盡最大努力,但不保證結果。具體來說,路徑上會發生這些事。
在這個地基之上,代替應用程式承接「讓檔案 1 個位元組都不缺、按照順序送達」這份工作的,就是 TCP(Transmission Control Protocol)。
IP 只到「大概會送到」為止。在其上,TCP 守住 3 項承諾,UDP 則刻意幾乎原樣放行。不是誰比較偉大,而是角色不同。
TCP 的 3 項承諾 — 本課程的骨幹
TCP 的機制乍看很多,但全部都是為了守住下列 3 項承諾之一的工具。本課程每一章都會回頭確認,現在學的機制是為了哪一項承諾。
| 承諾 | 意義 | 實現的工具 | 涵蓋章節 |
|---|---|---|---|
| 一定送達 — 沒送到就會發現 | 缺了就偵測並重傳 | 序號 + ACK + 重傳計時器 | 第 2〜3 章 |
| 按照順序 | 修正亂序與重複後再交付 | 序號 + 接收緩衝區 | 第 3 章、第 6 章 |
| 配合對方與網路的步調 | 不比接收端與路徑的狀況更快傳送 | 視窗(流量控制)+ cwnd(壅塞控制) | 第 4〜5 章 |
另一方面,UDP(User Datagram Protocol)刻意不做這些承諾。它是在 IP 的盡力而為之上,只加了「連接埠號」與最低限度檢查的薄層。這不是偷工減料,而是為了重傳與順序等待反而礙事的用途(視訊通話、線上遊戲、DNS 查詢等)準備的選項。因為 TCP 的 3 項承諾,必然附帶延遲這個成本。
練習 1-1 — IP 的性質與 TCP/UDP 的分工
能正確說出「IP 不會替你做什麼」,是理解 TCP 的出發點。
Q1. 只用 IP(沒有 TCP)傳送資料時,路徑上正常情況下就可能發生的事,正確的組合是哪一個?
IP 的遞送是「盡力而為(best effort)」。封包會因路由器佇列溢出而被丟棄、因路徑不同而被超車、因重送機制的副作用而重複。而且 IP 自己既不偵測也不通知。接受這個「什麼都不保證的地基」,正是 TCP 設計的起點。順序被保持、一定送達、異常會被通知,這些都是 IP 沒有的性質。
Q2. 適合選擇 UDP 而非 TCP 的場景是哪一個?
UDP 是把 IP 的盡力而為幾乎原封不動交給應用程式的薄層。視訊通話中,就算把 0.1 秒前的語音重傳回來也已經太遲,「缺了就放棄、往下走」的體驗反而更好,所以適合 UDP。檔案傳輸與郵件連 1 個位元組都不容許缺失,屬於 TCP 的守備範圍。另外,防竄改既不是 TCP 也不是 UDP 的工作,而是 TLS 等機制的職責。
Q3. TCP 沒有承諾的事情是哪一個?
TCP 承諾「一定送達(沒送到就會發現)、按照順序、配合對方與網路」,但任何地方都沒有時間的保證。反而因為重傳與等待,延遲只會往增加的方向走。「明明是 TCP 卻很慢」不是違約,而是即使變慢也要守住承諾的樣子 — 這個觀點會成為本課程的地基。
連接埠號與 socket — 指定對話的窗口
IP 位址指向「哪一台主機」,但送達的那台主機上,Web 伺服器、資料庫、SSH 都同時在運作。指出是給那台主機的哪一個程式的另一個號碼,就是連接埠號(0〜65535。HTTPS 是 443、SSH 是 22 等)。
而 IP 位址 : 連接埠號 這組值所指的通訊窗口,稱為 socket。從程式的角度看,socket 是「連到對方的位元組水管」,用 send() 灌入、用 recv() 接收(這條水管出人意料的性質,是第 6 章的主角)。
這裡重要的是,識別一條 TCP 連線的不是只有目的地。連線是以
(來源 IP, 來源連接埠, 目的 IP, 目的連接埠)
這個四元組來識別的。所以幾萬個用戶端可以同時連到同一台伺服器的連接埠 443 — 即使目的端相同,只要來源端的 IP 或連接埠(用戶端這側會自動分配空閒的號碼)不同,就是不同的連線。
本課程的口訣:看到封包擷取或故障記錄時請先問自己 — 現在快被打破的,是送達的承諾?順序?還是步調的配合?
練習 1-2 — 連接埠號與 socket
確認光有 IP 位址還不夠的「另一個號碼」扮演什麼角色。
Q4. 在 IP 位址之外還需要連接埠號的理由,正確的是哪一個?
IP 位址只能指到「哪一台主機」為止。一台主機上會有 Web 伺服器、SSH、資料庫等多個程式同時等待通訊,所以需要另一個號碼來指出「那台主機的哪一個窗口」。這就是連接埠號(例:HTTPS 是 443)。路由器只看 IP 位址轉送,加密則是 TLS 等機制的工作。
Q5. 許多用戶端可以同時連到同一台伺服器的連接埠 443。伺服器之所以能不搞混地區分每一條連線,是為什麼?
連線的識別子不是目的地那一個點,而是 (來源 IP, 來源連接埠, 目的 IP, 目的連接埠) 的四元組。即使目的端全都是 443,只要來源端的 IP 或連接埠不同,就是不同的連線。這個四元組的其中一端,也就是自己這側的 IP:連接埠 這個通訊窗口,就是 socket。四元組在第 2 章的 TIME_WAIT 與第 7 章的案例中也會是主角。
本章帶走的重點
- IP 是盡力而為 — 會遺失、打亂、重複,而且不通知
- TCP 的承諾有 3 項 — 一定送達(沒送到就會發現)、按照順序、配合對方與網路。沒有時間的保證
- UDP 是用承諾換取低延遲的選項。依用途分開使用
- 連線以 (來源 IP, 來源連接埠, 目的 IP, 目的連接埠) 的四元組來識別
下一章將逐一封包地追蹤這個四元組的兩端達成「接下來要開始數號碼囉」共識的儀式 — 三向交握。