Learning Objectives
- 說明傳輸層的工作:IP 把封包送到主機,連接埠把資料交給主機上正確的程式
- 說出連接埠號碼的三個範圍,以及常見服務的知名埠
- 用來源位址、來源埠、目的位址、目的埠四個值(四元組)分辨一條通訊
- 說明 UDP 不建立連線、不保證送達、不保證順序的特性,以及適合用 UDP 的應用
- 用 Python 的 SOCK_DGRAM 寫 UDP 用戶端,用 settimeout 處理遺失,必要時自己重送
封包到了電腦,要交給哪一個程式
前面十幾課都在處理同一件事:讓 IP 封包從一台主機走到另一台主機。可是一台電腦上同時有很多程式在用網路: 瀏覽器開著好幾個分頁、通訊軟體在收訊息、系統在背景校時。封包抵達電腦之後,作業系統要怎麼知道該交給誰?
這是傳輸層(第 4 層)的工作。計算機概論第 30 課提過 TCP 與 UDP,這一課先看比較簡單的 UDP,以及兩者共用的連接埠(port)。
| 層 | 用什麼定位 | 負責把資料送到 |
|---|---|---|
| 網路層(IP) | IP 位址 | 正確的主機 |
| 傳輸層(TCP、UDP) | 連接埠號碼 | 主機上正確的程式(更精確地說,是程式開的 socket) |
連接埠是一個 16 位元的數字,範圍 0~65535。傳輸層的標頭裡有來源埠與目的埠兩個欄位: 目的埠決定交給對方的哪個程式,來源埠讓對方知道回覆要送回哪裡。
連接埠的範圍與四元組
IANA(網際網路號碼分配機構)依 RFC 6335 把連接埠分成三段:
| 範圍 | 名稱 | 用途 |
|---|---|---|
| 0~1023 | 系統埠(知名埠,well-known ports) | 常見的標準服務;許多作業系統只允許管理者權限的程式使用 |
| 1024~49151 | 使用者埠(登記埠,registered ports) | 向 IANA 登記的應用程式 |
| 49152~65535 | 動態埠(私有埠、暫時埠,ephemeral ports) | 不分配給任何服務,給用戶端臨時使用 |
常見的服務與連接埠:
| 服務 | 傳輸協定 | 連接埠 |
|---|---|---|
| DNS | 主要用 UDP(回答太大時改用 TCP) | 53 |
| DHCP | UDP | 伺服器 67、用戶端 68 |
| NTP(校時) | UDP | 123 |
| SSH | TCP | 22 |
| HTTP/HTTPS | TCP | 80/443 |
伺服器固定聽一個大家知道的連接埠;用戶端的連接埠通常由作業系統自動挑一個沒在用的動態埠。 實際挑選的範圍依系統設定而不同,例如 Windows 預設用 49152~65535,許多 Linux 發行版預設用 32768~60999。
一條通訊由四個值決定,叫做 socket 的四元組(再加上協定是 TCP 還是 UDP):
(來源 IP, 來源埠, 目的 IP, 目的埠)
(192.168.1.10, 49153, 192.168.1.20, 9999)
同一台電腦連到同一個伺服器的同一個埠好幾次,只要來源埠不同,就是不同的通訊,回覆也不會送錯。下面的範例實際看看。
逐步看:兩個 socket,兩個來源埠
模擬網路裡,你的電腦是 PC1(192.168.1.10),伺服器 SRV(192.168.1.20)的 UDP 9999 埠上有一個程式, 會把收到的文字轉成大寫送回來。注意上方時序圖每一個 UDP 資料報標示的兩個連接埠。
UDP:寄出就好
UDP(User Datagram Protocol,使用者資料報協定,RFC 768)幾乎只在 IP 上面加了連接埠:
0 16 31(位元)
+---------------+---------------+
| 來源埠 | 目的埠 |
+---------------+---------------+
| 長度(含標頭)| 校驗和 |
+---------------+---------------+
| 資料 ... |
標頭固定 8 位元組,四個欄位各 2 位元組;TCP 的標頭至少 20 位元組。UDP 的特性:
| 特性 | 意思 |
|---|---|
| 不建立連線 | 不必先「打招呼」,第一個資料報就帶著資料直接送出 |
| 不保證送達 | 遺失了不會重送,送出的一方也不會知道 |
| 不保證順序 | 先送的可能後到,接收端照抵達的順序收 |
| 保留訊息邊界 | 每次 sendto 是一個完整的資料報,對方每次 recvfrom 收到一整個,不會被拆開或黏在一起 |
| 沒有流量與壅塞控制 | 想送多快就送多快,網路塞不塞由應用程式自己注意 |
聽起來都是缺點,但「不等、不重送」在很多應用正好是優點:
| 應用 | 為什麼用 UDP |
|---|---|
| DNS 查詢 | 一問一答,多數回答一個資料報就裝得下;沒收到就再問一次,比先建立連線快 |
| 語音、視訊串流、線上會議 | 晚到的聲音已經沒用;寧可跳過一小段,也不要卡住等重送 |
| 線上遊戲 | 位置每秒更新很多次,最新的狀態比舊的重要 |
| 感測器回報 | 每隔幾秒送一次讀數,少一筆,下一筆很快就來 |
| DHCP | 還沒有 IP 位址時只能廣播,沒辦法先建立連線 |
需要可靠又想要 UDP 的彈性時,應用程式可以在 UDP 上自己加上確認與重送;HTTP/3 用的 QUIC 就是建在 UDP 上的傳輸協定。
逐步看:UDP 用戶端
一個 UDP 用戶端只需要四個動作:建立 socket、sendto、recvfrom、close。注意時序圖上沒有任何「建立連線」的封包,第一個送出的就是資料。
逐步看:第 2 個資料報遺失了
這次模擬網路會讓第 2 個往外送的資料報在路上遺失(時序圖上畫成中途斷掉)。 UDP 不會重送,程式只能用逾時發現「等太久了」。注意時間:遺失的那一輪,程式整整等了 0.5 秒。
逐步看:應用程式自己重送
需要每一筆都送到時,就在應用程式裡加上「逾時就重送」。這次模擬網路讓第 2、3 個往外送的資料報都遺失,
看 ask 函數怎麼試到第 3 次才成功。DNS 用戶端就是用類似的做法:問了沒回答,就再問一次或換一台伺服器問。
小測驗:連接埠與四元組
瀏覽器連到網頁伺服器的 443 埠時,瀏覽器這一端的連接埠通常是?
下列哪一個連接埠落在 IANA 的「動態埠」範圍?
同一台電腦同時開了兩個分頁,都連到 203.0.113.80 的 443 埠。伺服器怎麼分辨兩條連線?
小測驗:UDP 的特性
線上會議的語音通常用 UDP 傳送,最主要的原因是?
用戶端用 UDP 連續 sendto 了三次,各 100 位元組。伺服器每次 recvfrom(1024) 會收到什麼(假設都沒有遺失)?
UDP 標頭有哪四個欄位?
重點整理
- 傳輸層用連接埠把資料交給主機上正確的程式;連接埠是 0~65535 的 16 位元數字。
- IANA 的三個範圍:系統埠 0~1023、使用者埠 1024~49151、動態埠 49152~65535;用戶端的來源埠通常由作業系統自動挑選。
- 一條通訊由四元組(來源 IP、來源埠、目的 IP、目的埠)加上協定決定。
- UDP:標頭 8 位元組、不建立連線、不保證送達與順序、保留訊息邊界;適合 DNS、即時影音、遊戲、感測器回報。
- Python:
socket(AF_INET, SOCK_DGRAM)、sendto、recvfrom;用settimeout避免永遠等待,需要可靠時自己重送。
UDP 把可靠性留給應用程式。如果每個程式都要自己處理遺失、重複、順序和網路壅塞,負擔很重。 下一課開始看 TCP:它怎麼建立連線,以及用序號與確認號保證資料完整、依序送達。