Mímisbrunnr知恵の泉

← コンピュータネットワーク 一覧

🎓 レベル:標準 | 重要度:A(必須) 📎 前提:カプセル化とデータの流れ

要点(BLUF)

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・確立完了)

終了は FIN を使った4ウェイ(双方向に独立して閉じる)で行います。

シーケンス番号と確認応答(ACK)

TCPは**バイトに通し番号(シーケンス番号)**を振ります。受信側は「次に欲しいバイト番号」を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が長い)回線では、ウィンドウが小さいと帯域が太くても速度が出ません。これが「帯域遅延積」の直観で、長距離回線では大きなウィンドウが要ります。

輻輳制御:網全体を詰まらせない

フロー制御が「受信側の都合」なら、輻輳制御は「途中の網の都合」です。送信側は輻輳ウィンドウを持ち、

このため、TCPは利用可能な帯域を探りながら自律的に速度を調整します。

なぜTCPはコネクションを張るのか(設計の直観)

IPは1パケットごとに独立で、状態を持ちません。一方「確実に順序通り届ける」には、両端が共通の状態(次は何番か、どこまで届いたか)を持つ必要があります。3ウェイハンドシェイクはその状態を立ち上げる儀式で、初期シーケンス番号を乱数にするのは古いパケットの混入やなりすましを防ぐためです。信頼性は「下の層の保証」ではなく「両端の合意と記録」で作る——これがTCPの核心です。

⚠️ よくある誤解

対応 lab

関連