小村軟體有限公司
第 1 章

導入 — TCP 承諾了什麼

從只有 IP 的世界會不送達、亂序、重複的前提出發,掌握 TCP 的 3 項承諾與 UDP 的分工,以及連接埠號與 socket 的角色。

過不了「已逾時」這一關

找到了連線逾時的記錄。重試之後就好了。但「為什麼」始終不明 — TCP 的故障調查,多數人都停在這裡。因為就算打開封包擷取,也讀不懂 seqackwin 這一排數字在說什麼。

學會閱讀的捷徑,不是把 TCP 的功能背起來,而是先掌握 TCP 站在什麼樣的地基上、想要承諾什麼。出發點是位於 TCP 之下的 IP 的性質。IP 會把封包(資料的小包裹)運送到目的主機,但這個遞送是「盡力而為(best effort)」— 盡最大努力,但不保證結果。具體來說,路徑上會發生這些事。

可能送不到
壅塞的路由器會默默丟棄溢出的封包。丟棄這件事不會通知任何人
順序可能互換
如果每個封包走的路徑不同,後送出的可能先到
可能重複
重送機制與遞送延遲疊在一起時,同一個封包會送達 2 次

在這個地基之上,代替應用程式承接「讓檔案 1 個位元組都不缺、按照順序送達」這份工作的,就是 TCP(Transmission Control Protocol)

在會遺失、打亂、重複的 IP 之上疊著 TCP 與 UDP,由 TCP 向應用程式提供一定送達、按照順序、配合步調這 3 項承諾的層級結構圖

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)傳送資料時,路徑上正常情況下就可能發生的事,正確的組合是哪一個?

Q2. 適合選擇 UDP 而非 TCP 的場景是哪一個?

Q3. 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 位址之外還需要連接埠號的理由,正確的是哪一個?

Q5. 許多用戶端可以同時連到同一台伺服器的連接埠 443。伺服器之所以能不搞混地區分每一條連線,是為什麼?

本章帶走的重點

  • IP 是盡力而為 — 會遺失、打亂、重複,而且不通知
  • TCP 的承諾有 3 項 — 一定送達(沒送到就會發現)、按照順序、配合對方與網路。沒有時間的保證
  • UDP 是用承諾換取低延遲的選項。依用途分開使用
  • 連線以 (來源 IP, 來源連接埠, 目的 IP, 目的連接埠) 的四元組來識別

下一章將逐一封包地追蹤這個四元組的兩端達成「接下來要開始數號碼囉」共識的儀式 — 三向交握。