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 16

TCP(一):連線的建立與結束

三向交握、序號與確認號、連線的狀態
Interaction 25 minute(s)

Learning Objectives

  • 說出 TCP 在 IP 之上提供的保證:連線導向、可靠、依序、位元組流
  • 說明序號與確認號的意思,並算出每個封包的 seq 與 ack
  • 描述三向交握的三個封包,以及為什麼需要三個
  • 描述四次揮手與半關閉,說出 FIN-WAIT、CLOSE-WAIT、TIME-WAIT 等狀態的意思
  • 分辨連線被拒絕(RST)和完全沒有回應(逾時)兩種失敗

在不可靠的網路上做出可靠的傳輸

上一課的 UDP 寄出就好,遺失、重複、亂序都留給應用程式處理。可是大部分應用需要的是「送出去的東西,對方一定完整、依序收到」: 網頁、檔案下載、電子郵件、SSH 遠端登入都是如此。這些應用都用 TCP(Transmission Control Protocol,傳輸控制協定)。

TCP 的規格最早是 1981 年的 RFC 793,2022 年由 RFC 9293 整合後取代。它在「盡力而為」的 IP 上面提供:

保證 意思 靠什麼做到
連線導向 傳資料之前兩端先建立連線,結束時也要關閉 三向交握、四次揮手(本課)
可靠 遺失的會重送,重複的會丟掉 序號、確認、重傳(下一課)
依序 應用程式讀到的順序就是對方寫入的順序 序號,接收端重新排好
位元組流 沒有訊息邊界:送三次 100 位元組,對方可能一次讀到 300 序號以位元組為單位
流量控制、壅塞控制 不送得比接收端或網路能承受的快 視窗(下一課)

計算機概論第 30 課用一句話帶過三向交握;這一課逐一看每個封包裡的數字。

序號、確認號與旗標

TCP 標頭至少 20 位元組,除了來源埠、目的埠,這一課最重要的是下面幾個欄位:

欄位 大小 意思
序號(sequence number,seq) 32 位元 這個區段的資料,第一個位元組的編號
確認號(acknowledgment number,ack) 32 位元 我下一個期待收到的位元組編號,也就是「這之前的我都收到了」
旗標 各 1 位元 SYN(同步序號,建立連線)、ACK(確認號有效)、FIN(我送完了)、RST(重設連線)、PSH 等
視窗(window) 16 位元 我的接收緩衝區還能收多少位元組(下一課)

TCP 傳的單位叫區段(segment)。三條規則把所有數字串起來:

  1. 序號以位元組計:送出 100 位元組、seq=1001,下一個區段的 seq 就是 1101。
  2. SYN 和 FIN 各佔一個序號,即使沒有帶資料,所以它們也需要被確認。
  3. 確認號是累積的:ack=1101 表示 1101 之前的位元組全部收到,不必逐一確認每個區段。

每條連線兩個方向各有一套序號,起點叫初始序號(ISN)。RFC 9293 建議用時鐘加上只有本機知道的秘密值來產生初始序號, 讓外人猜不到,避免偽造的封包被當成這條連線的一部分。下面的模擬器為了好讀,固定用 1000(用戶端)與 5000(伺服器)。

三向交握

建立連線之前,伺服器要先在某個連接埠上等待(呼叫 listen(),狀態 LISTEN),用戶端呼叫 connect() 時送出三個封包:

順序 方向 旗標 seq ack 意思 送出後的狀態
1 用戶端 → 伺服器 SYN 1000 - 我的序號從 1000 開始 用戶端 SYN-SENT
2 伺服器 → 用戶端 SYN、ACK 5000 1001 收到你的 1000(SYN 佔一號,所以期待 1001);我的序號從 5000 開始 伺服器 SYN-RECEIVED
3 用戶端 → 伺服器 ACK 1001 5001 收到你的 5000,期待 5001 兩端 ESTABLISHED

為什麼要三個,不是兩個?兩個方向的序號都要送出並被對方確認:第 1、2 個封包讓伺服器知道用戶端的起點並回覆確認, 第 2、3 個封包讓用戶端的確認回到伺服器。少了第 3 個,伺服器無法確定用戶端真的收到了它的初始序號, 也分辨不出這個 SYN 是不是網路上延遲很久、早就作廢的舊封包。

如果伺服器那個連接埠上沒有程式在 LISTEN,它會回一個 RST,用戶端立刻知道「連線被拒絕」(Python 會丟出 ConnectionRefusedError)。 如果 SYN 在路上遺失,用戶端收不到任何回覆,等逾時之後重送 SYN;一直沒回應,最後才放棄。

互動練習:一條連線從建立到結束

上方按鈕代表兩端的程式呼叫 socket 函數。時序圖往下是時間:每一條斜線是一個區段,標出種類、seq、ack;兩側是每一端的狀態變化。 很久沒有封包的時段會壓縮成「經過幾毫秒」。下方表格列出同樣的區段。

傳資料時的 seq 與 ack

連線建立後,兩個方向可以同時傳資料(全雙工),每個區段都帶著 ACK 旗標與最新的確認號。延續剛才的數字:

方向 內容 seq ack 說明
用戶端 → 伺服器 100 位元組資料 1001 5001 資料編號 1001~1100
伺服器 → 用戶端 ACK 5001 1101 1100 之前都收到,期待 1101
伺服器 → 用戶端 100 位元組資料 5001 1101 資料編號 5001~5100;確認號照樣帶著
用戶端 → 伺服器 ACK 1101 5101 期待 5101

注意兩件事:

  • 沒有帶資料的 ACK 不佔序號,所以伺服器送完 ACK 之後,自己的資料仍然從 5001 開始。
  • 確認號只說「到哪裡為止全部收到」。如果中間缺了一段,後面收到的再多,確認號也停在缺口的開頭。下一課會看到這件事怎麼觸發重傳。

模擬器裡接收端每收到一個區段就立刻確認;實際系統常會稍等一下,把幾個確認合併,或搭在要送出的資料上一起送(延遲確認)。

小測驗:序號與確認號

1.

用戶端的初始序號是 3000。三向交握中,伺服器回覆的 SYN-ACK 確認號是多少?

2.

連線建立後,用戶端連續送出兩個區段:seq=3001、len=500,以及 seq=3501、len=200。伺服器兩個都收到後的確認號是?

3.

三向交握為什麼不能只用兩個封包(SYN、SYN-ACK)?

4.

用戶端 connect() 之後立刻收到 RST。最可能的原因是?

第 1 次作答

四次揮手與連線狀態

關閉連線時,兩個方向要各自關閉,所以通常需要四個封包。先呼叫 close() 的一方叫主動關閉:

順序 方向 旗標 狀態變化
1 用戶端 → 伺服器 FIN 用戶端:ESTABLISHED → FIN-WAIT-1(我不再送資料了)
2 伺服器 → 用戶端 ACK 伺服器 → CLOSE-WAIT;用戶端收到後 → FIN-WAIT-2
3 伺服器 → 用戶端 FIN 伺服器的程式也 close() 後才送;伺服器 → LAST-ACK
4 用戶端 → 伺服器 ACK 用戶端 → TIME-WAIT;伺服器收到後 → CLOSED

第 2 與第 3 個封包之間,伺服器處於 CLOSE-WAIT:它知道對方不再送資料了,但自己還可以繼續送,直到程式呼叫 close()。 這叫半關閉。如果伺服器程式忘了關閉 socket,連線會一直停在 CLOSE-WAIT。

主動關閉的一方最後要在 TIME-WAIT 等待 2×MSL(MSL 是封包在網路上最長的存活時間,RFC 9293 取 2 分鐘),原因有兩個:

  1. 最後一個 ACK 可能遺失。對方會重送 FIN,自己還在 TIME-WAIT 就能再確認一次。
  2. 讓這條連線還在網路上漂流的舊封包全部消失,不會混進之後用同樣四元組建立的新連線。

RFC 9293 定義的狀態:

狀態 意思
CLOSED 沒有連線(概念上的狀態)
LISTEN 伺服器等待連線
SYN-SENT/SYN-RECEIVED 三向交握進行中
ESTABLISHED 連線建立,可以傳資料
FIN-WAIT-1/FIN-WAIT-2 主動關閉方:送出 FIN,等確認、等對方的 FIN
CLOSE-WAIT 被動關閉方:收到 FIN,等自己的程式關閉
LAST-ACK 被動關閉方:送出 FIN,等最後的確認
CLOSING 兩邊幾乎同時送出 FIN
TIME-WAIT 主動關閉方等待 2×MSL

在自己的電腦上可以用 netstat -an(Windows、macOS)或 ss -tan(Linux)列出每條 TCP 連線的四元組與狀態; 實際系統 TIME-WAIT 等多久依作業系統而定。另外,任何一方都可以送 RST 直接中止連線,不走四次揮手。

互動練習:在網路上看真的三向交握

回到網路模擬器。http 指令會先完成三向交握,再送出一個 HTTP 請求。執行後點下方封包紀錄的每一列,看 TCP 欄位裡的旗標、序號與確認號。 這個模擬器只畫出建立連線與一次請求、回應,沒有畫結束連線;初始序號同樣固定成 1000 與 5000。

小測驗:關閉連線與狀態

1.

一台伺服器上看到大量連線停在 CLOSE-WAIT,最可能的原因是?

2.

四次揮手後,哪一方要在 TIME-WAIT 等待 2×MSL?

3.

用戶端送出 FIN、伺服器回了 ACK,但伺服器還沒送出自己的 FIN。這段時間伺服器可以做什麼?

第 1 次作答

重點整理

  • TCP 在 IP 上提供連線導向、可靠、依序的位元組流;規格是 RFC 9293。
  • 序號以位元組計,SYN 與 FIN 各佔一個;確認號=下一個期待的位元組編號,而且是累積的。
  • 三向交握:SYN → SYN-ACK → ACK,兩個方向的初始序號都被確認;沒有程式在聽會收到 RST。
  • 四次揮手:兩個方向各自 FIN、各自確認;被動方在 CLOSE-WAIT 還能送資料(半關閉),主動方最後在 TIME-WAIT 等 2×MSL。
  • 收到 RST=主機在、但拒絕;完全沒有回應=主機不在、封包被丟掉或擋掉,只能等逾時。

這一課的封包都沒有遺失(除了你刻意弄丟的 SYN)。下一課讓資料在路上遺失,看 TCP 怎麼靠確認與重傳補回來, 以及怎麼決定一次能送多少:滑動視窗、流量控制與壅塞控制。

這一課完成了!
Next lesson:TCP(二):可靠傳輸與壅塞控制
你目前沒有登入,學習進度只存在這個瀏覽器。 Login 後,進度會跟著帳號,換電腦也看得到。