跳至主要內容
Skip to content

深入淺出 TCP 協定:網路傳輸的可靠基石

在 HTTP 請求的旅程中,TCP (Transmission Control Protocol) 扮演著「搬運工」的角色。它不關心傳輸的是什麼,但它保證資料一定會安全、有序且完整地送達目的地。我們將通過這篇文章深入探討這個網路世界的基石。


一、 TCP 的核心特性

TCP 是一個面向連接的 (Connection-oriented)可靠的基於位元組流 (Byte Stream) 的傳輸層協定。它的偉大之處在於解決了通訊中的不確定性。

特性說明
可靠性通過序列號與確認應答 (ACK) 確保封包不遺失
有序性即使封包到達順序錯亂,接收端也能按序重組
流量控制根據接收端的處理能力動態調整發送速度
擁塞控制當網路擁塞時,主動降低發送量以避免崩潰

二、 三向交握:建立連線的藝術

在傳輸任何應用層資料(如 HTTP)之前,TCP 必須先建立連線。這個過程稱為「三向交握」,目的是確認雙方都具備發送與接收的能力。

> **為什麼是三次?** 兩次無法確認雙方的收發能力皆正常,四次則顯得冗餘。三次是達成連線共識的最精簡路徑。


三、 四次揮手:優雅地結束連線

連線的拆除與建立同樣重要。TCP 使用「四次揮手」來確保雙方都已經處理完所有剩餘的資料。


四、 錯誤處理機制

TCP 的「可靠」不是天生的,而是靠一套精密的重傳機制實現的:

  1. 超時重傳 (Timeout Retransmission):如果發送端在一定時間內沒收到 ACK,就會重新發送。
  2. 快速重傳 (Fast Retransmission):如果連續收到三個相同的冗餘 ACK,代表中間有封包遺失,會立刻重傳。
  3. 校驗和 (Checksum):確保資料在傳輸過程中沒有被雜訊干擾而損壞。

五、 核心術語詳解

在理解 TCP 的運作流程後,讓我們深入了解這些關鍵術語的真正含義:

5.1 連線建立階段

SYN (Synchronize Sequence Number)

同步序列號

  • 用途:請求建立連線,並告知對方自己的初始序列號
  • 封包標誌位:TCP Header 中的 SYN flag 設為 1
  • 攜帶資訊
    • 初始序列號 (Initial Sequence Number, ISN),例如 seq=1000
    • 視窗大小 (接收緩衝區大小)
    • MSS (Maximum Segment Size) 等選項
  • 實際意義:「我想跟你建立連線,我的起始編號是 1000」
SYN 封包範例:
flags: [SYN]
seq: 1000
ack: 0 (尚未確認任何資料)
window: 65535

ACK (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-1999

Ack 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 配對:

  1. 客戶端 → 伺服器:FIN (我要關閉)
  2. 伺服器 → 客戶端:ACK (收到,但我可能還有資料)
  3. 伺服器 → 客戶端:FIN (我也要關閉了)
  4. 客戶端 → 伺服器:ACK (收到,連線結束)

5.4 術語關係圖


總結

階段關鍵術語目的
連線建立SYN, ACK (三向交握)確認雙方收發能力,同步初始序列號
資料傳輸Seq, Ack, Window Size確保可靠、有序且具備流量控制
連線釋放FIN, ACK (四次揮手)確保資料完整交換後優雅斷開

進階挑戰

  1. 思考一下,如果三向交握中第三次的 ACK 封包在網路中遺失了,伺服器會如何反應?
  2. 使用 tcpdump 或 Wireshark 觀察一次真實的 HTTP 請求,找出其中的 SYN 與 FIN 標誌位。

延伸閱讀與資源