🎓 レベル:標準 | 重要度:A(必須) 📎 前提:カプセル化とデータの流れ
要点(BLUF)
- TCPは、信頼性のないIPの上に順序保証・欠落の再送・重複排除を載せ、「送ったデータが、送った順で、確実に届く」通信を作ります。
- 通信前に3ウェイハンドシェイクでコネクションを確立し、お互いの初期シーケンス番号を同期します。
- 受信側の処理速度に合わせるフロー制御(ウィンドウ)と、網の混雑に合わせる輻輳制御で、速度を動的に調整します。
3ウェイハンドシェイク:会話を始める
データを送る前に、両者が「これから話す」と合意し、シーケンス番号の初期値を交換します。
sequenceDiagram
participant C as クライアント
participant S as サーバ
C->>S: SYN(seq=x・接続したい)
S->>C: SYN・ACK(seq=y・ack=x+1・了解)
C->>S: ACK(ack=y+1・確立完了)
- SYN:接続要求。自分の初期シーケンス番号 x を伝える。
- SYN+ACK:サーバが応答し、自分の y を伝えつつ x を確認。
- ACK:クライアントが y を確認。これで双方向の準備が整います。
終了は FIN を使った4ウェイ(双方向に独立して閉じる)で行います。
シーケンス番号と確認応答(ACK)
TCPは**バイトに通し番号(シーケンス番号)**を振ります。受信側は「次に欲しいバイト番号」をACKで返します。
- 届かなければ送信側はタイムアウトまたは重複ACKを検知して再送。
- 順序が乱れて届いても、番号順に並べ直して上位へ渡す。
- 同じ番号が二度来たら重複を破棄。
これにより、IPがパケットを落とそうが順序を入れ替えようが、アプリには整然としたバイト列が届きます。
フロー制御:受信側を溢れさせない
受信側は自分のバッファの空き容量をウィンドウサイズとして広告します。送信側はACKを待たずにウィンドウ分まで連続送信でき、受信側が遅ければウィンドウを縮めて送信を絞ります。
graph LR S["送信側:ウィンドウ内は連続送信可"] R["受信側:空き容量をウィンドウで広告"] S -->|"データ"| R R -->|"ACK + 新ウィンドウ"| S
# スループットの上限はおおよそ ウィンドウサイズ / RTT で決まる
window_bytes = 64 * 1024 # 64KiB ウィンドウ
rtt_sec = 0.04 # 往復遅延 40ms
throughput_bps = window_bytes * 8 / rtt_sec
print("window bytes :", window_bytes)
print("RTT seconds :", rtt_sec)
print("throughput :", round(throughput_bps / 1e6, 2), "Mbps")
実行結果:
window bytes : 65536
RTT seconds : 0.04
throughput : 13.11 Mbps
遅延が大きい(RTTが長い)回線では、ウィンドウが小さいと帯域が太くても速度が出ません。これが「帯域遅延積」の直観で、長距離回線では大きなウィンドウが要ります。
輻輳制御:網全体を詰まらせない
フロー制御が「受信側の都合」なら、輻輳制御は「途中の網の都合」です。送信側は輻輳ウィンドウを持ち、
- 開始時は小さく、ACKが順調なら指数的に増やす(スロースタート)。
- パケット損失を混雑のサインとみなし、ウィンドウを一気に絞る。
このため、TCPは利用可能な帯域を探りながら自律的に速度を調整します。
なぜTCPはコネクションを張るのか(設計の直観)
IPは1パケットごとに独立で、状態を持ちません。一方「確実に順序通り届ける」には、両端が共通の状態(次は何番か、どこまで届いたか)を持つ必要があります。3ウェイハンドシェイクはその状態を立ち上げる儀式で、初期シーケンス番号を乱数にするのは古いパケットの混入やなりすましを防ぐためです。信頼性は「下の層の保証」ではなく「両端の合意と記録」で作る——これがTCPの核心です。
⚠️ よくある誤解
- 「TCPなら絶対に速い/遅い」ではない。TCPは信頼性のための往復確認が要るため、損失の多い回線や超低遅延が要る用途ではUDPが有利な場面があります。
- 「3ウェイのSYNは2回」ではない。SYN→SYN+ACK→ACKの3つ。SYN+ACKを1つにまとめている点が「3ウェイ」たるゆえん。
- 「ウィンドウサイズが大きいほど常に速い」ではない。受信バッファや網の混雑を超えると損失が増え、かえって遅くなります。フロー制御と輻輳制御の両方で抑えられます。
対応 lab
[[networking-study/labs/04-01_tcp_throughput.py]]— 帯域遅延積とウィンドウからスループット上限を試算
関連
- 対になる軽量プロトコル:
[[04-02_UDP]]/アプリの識別:[[04-03_ポートとソケット]] - 上で動くアプリ:
[[05-02_HTTP_HTTPS]]/信頼性が要らない例:[[05-01_DNS]]