深入淺出 TCP 協定:網路傳輸的可靠基石
在 HTTP 請求的旅程中,TCP (Transmission Control Protocol) 扮演著「搬運工」的角色。它不關心傳輸的是什麼,但它保證資料一定會安全、有序且完整地送達目的地。我們將通過這篇文章深入探討這個網路世界的基石。
一、 TCP 的核心特性
TCP 是一個面向連接的 (Connection-oriented)、可靠的、基於位元組流 (Byte Stream) 的傳輸層協定。它的偉大之處在於解決了通訊中的不確定性。
| 特性 | 說明 |
|---|---|
| 可靠性 | 通過序列號與確認應答 (ACK) 確保封包不遺失 |
| 有序性 | 即使封包到達順序錯亂,接收端也能按序重組 |
| 流量控制 | 根據接收端的處理能力動態調整發送速度 |
| 擁塞控制 | 當網路擁塞時,主動降低發送量以避免崩潰 |
二、 三向交握:建立連線的藝術
在傳輸任何應用層資料(如 HTTP)之前,TCP 必須先建立連線。這個過程稱為「三向交握」,目的是確認雙方都具備發送與接收的能力。
> **為什麼是三次?** 兩次無法確認雙方的收發能力皆正常,四次則顯得冗餘。三次是達成連線共識的最精簡路徑。
三、 四次揮手:優雅地結束連線
連線的拆除與建立同樣重要。TCP 使用「四次揮手」來確保雙方都已經處理完所有剩餘的資料。
四、 錯誤處理機制
TCP 的「可靠」不是天生的,而是靠一套精密的重傳機制實現的:
- 超時重傳 (Timeout Retransmission):如果發送端在一定時間內沒收到 ACK,就會重新發送。
- 快速重傳 (Fast Retransmission):如果連續收到三個相同的冗餘 ACK,代表中間有封包遺失,會立刻重傳。
- 校驗和 (Checksum):確保資料在傳輸過程中沒有被雜訊干擾而損壞。
五、 核心術語詳解
在理解 TCP 的運作流程後,讓我們深入了解這些關鍵術語的真正含義:
5.1 連線建立階段
SYN (Synchronize Sequence Number)
同步序列號
- 用途:請求建立連線,並告知對方自己的初始序列號
- 封包標誌位:TCP Header 中的 SYN flag 設為 1
- 攜帶資訊:
- 初始序列號 (Initial Sequence Number, ISN),例如
seq=1000 - 視窗大小 (接收緩衝區大小)
- MSS (Maximum Segment Size) 等選項
- 初始序列號 (Initial Sequence Number, ISN),例如
- 實際意義:「我想跟你建立連線,我的起始編號是 1000」
SYN 封包範例:
flags: [SYN]
seq: 1000
ack: 0 (尚未確認任何資料)
window: 65535ACK (Acknowledgment)
確認應答
- 用途:確認已成功接收對方的資料
- 封包標誌位:TCP Header 中的 ACK flag 設為 1
- 攜帶資訊:
ack欄位:期望接收的下一個序列號- 例如
ack=1001表示「我已收到序列號 1000 的資料,請從 1001 開始傳」
- 重要特性:在三向交握後,所有封包的 ACK flag 都會是 1
ACK 封包範例:
flags: [ACK]
seq: 2000
ack: 1001 (確認收到對方的 seq=1000)5.2 資料傳輸階段
Seq (Sequence Number)
序列號
- 用途:標記每個位元組的編號,確保資料有序到達
- 運作方式:
- 假設初始序列號是 1000
- 第一個封包傳送 100 bytes,seq=1000
- 第二個封包 seq=1100(1000 + 100)
- 第三個封包 seq=1200(1100 + 100)
- 解決問題:即使封包亂序到達(1200 → 1000 → 1100),接收端也能按序重組
資料傳輸範例:
封包 1: seq=1000, len=500 → 傳輸位元組 1000-1499
封包 2: seq=1500, len=300 → 傳輸位元組 1500-1799
封包 3: seq=1800, len=200 → 傳輸位元組 1800-1999Ack Number (Acknowledgment Number)
確認號
- 用途:告訴對方「我已收到哪些資料,請從哪裡繼續傳」
- 運作方式:
- 收到 seq=1000, len=500 的封包
- 回應 ack=1500(表示「1500 之前的都收到了,請傳 1500 開始的」)
- 累積確認:ack=1500 代表 1500 之前的所有位元組都已正確接收
確認應答範例:
接收到: seq=1000, len=500
回應: ack=1500 (期待下一個位元組從 1500 開始)Window Size (視窗大小)
接收視窗
- 用途:流量控制,告訴對方「我的接收緩衝區還能容納多少資料」
- 運作方式:
- 接收端 Window Size = 4096 bytes
- 表示「你最多可以一次發送 4096 bytes 給我」
- 如果應用程式處理不及,視窗會縮小甚至變成 0(停止發送)
- 動態調整:每個 ACK 都會更新視窗大小
視窗控制範例:
發送端可發送範圍:[ack, ack + window)
初始狀態:
ack=1000, window=4096 → 可發送 1000-5095
發送 2000 bytes 後:
ack=3000, window=2096 → 可發送 3000-5095 (視窗縮小)
應用程式處理完畢:
ack=3000, window=6096 → 可發送 3000-9095 (視窗擴大)5.3 連線釋放階段
FIN (Finish)
結束標誌
- 用途:通知對方「我這邊的資料已經傳送完畢,想要關閉連線」
- 封包標誌位:TCP Header 中的 FIN flag 設為 1
- 重要特性:
- FIN 是單向的,只代表發送方不再傳送資料
- 接收方仍可繼續發送未完成的資料(半關閉狀態)
- 需要雙方都發送 FIN 才能完全關閉連線
FIN 封包範例:
flags: [FIN, ACK]
seq: 5000 (最後一個位元組的序列號)
ack: 8000 (同時確認對方的資料)四次揮手中的 FIN + ACK 配對:
- 客戶端 → 伺服器:
FIN(我要關閉) - 伺服器 → 客戶端:
ACK(收到,但我可能還有資料) - 伺服器 → 客戶端:
FIN(我也要關閉了) - 客戶端 → 伺服器:
ACK(收到,連線結束)
5.4 術語關係圖
總結
| 階段 | 關鍵術語 | 目的 |
|---|---|---|
| 連線建立 | SYN, ACK (三向交握) | 確認雙方收發能力,同步初始序列號 |
| 資料傳輸 | Seq, Ack, Window Size | 確保可靠、有序且具備流量控制 |
| 連線釋放 | FIN, ACK (四次揮手) | 確保資料完整交換後優雅斷開 |
進階挑戰
- 思考一下,如果三向交握中第三次的 ACK 封包在網路中遺失了,伺服器會如何反應?
- 使用
tcpdump或 Wireshark 觀察一次真實的 HTTP 請求,找出其中的 SYN 與 FIN 標誌位。