TCP基礎
所要時間
約40分
学べること
- TCP/IPプロトコルスタックの概要
- TCPの特徴と役割(信頼性、順序保証、フロー制御)
- 3ウェイハンドシェイクと4ウェイハンドシェイク
- TCPの状態遷移(ESTABLISHED、TIME_WAIT等)
- ポート番号とソケット
- TCPとUDPの違いと使い分け
- HTTP、JDBC、Redis等がTCPをどう使っているか
- コネクションプールの仕組みと重要性
- 実運用でのTCPチューニング
前提知識
- ネットワークの基本概念(IPアドレス、パケット)
- OSI参照モデルまたはTCP/IPモデルの概要
1. TCP/IPプロトコルスタック
1.1 レイヤー構造
┌─────────────────────────────────────────────────────────────┐
│ TCP/IPプロトコルスタック │
├─────────────────────────────────────────────────────────────┤
│ │
│ OSI参照モデル TCP/IPモデル プロトコル例 │
│ ───────────────────────────────────────────────────────── │
│ │
│ 7. アプリケーション層 ┐ │
│ 6. プレゼンテーション層├─ アプリケーション層 HTTP, HTTPS, │
│ 5. セッション層 ┘ FTP, SSH, DNS │
│ │
│ 4. トランスポート層 ─── トランスポート層 TCP, UDP │
│ ↑ 今回の主役 │
│ │
│ 3. ネットワーク層 ─── インターネット層 IP, ICMP │
│ │
│ 2. データリンク層 ┐ │
│ 1. 物理層 ┘── ネットワーク Ethernet, │
│ インターフェース層 Wi-Fi │
│ │
└─────────────────────────────────────────────────────────────┘
1.2 データのカプセル化
┌─────────────────────────────────────────────────────────────┐
│ データのカプセル化 │
├─────────────────────────────────────────────────────────────┤
│ │
│ アプリケーション層 │
│ ┌───────────────────────────────────────────┐ │
│ │ データ (Payload) │ │
│ └───────────────────────────────────────────┘ │
│ ↓ │
│ トランスポート層 (TCP) │
│ ┌──────────┬───────────────────────────────┐ │
│ │ TCPヘッダ │ データ │ = セグメント │
│ └──────────┴───────────────────────────────┘ │
│ ↓ │
│ インターネット層 (IP) │
│ ┌─────────┬──────────┬─────────────────────┐ │
│ │ IPヘッダ │ TCPヘッダ │ データ │ = パケット │
│ └─────────┴──────────┴─────────────────────┘ │
│ ↓ │
│ ネットワークインターフェース層 (Ethernet) │
│ ┌───────────┬─────────┬──────────┬─────────┬─────┐ │
│ │Etherヘッダ│ IPヘッダ │ TCPヘッダ │ データ │ FCS │= フレーム│
│ └───────────┴─────────┴──────────┴─────────┴─────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
2. TCPの特徴
2.1 TCPが提供する機能
┌─────────────────────────────────────────────────────────────┐
│ TCPの主要機能 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. 信頼性のある通信 (Reliable Delivery) │
│ - パケットロスの検出と再送 │
│ - チェックサムによるデータ整合性検証 │
│ - ACK(確認応答)による到達確認 │
│ │
│ 2. 順序保証 (Ordered Delivery) │
│ - シーケンス番号による順序管理 │
│ - 到着順序が異なっても正しい順序で再構築 │
│ │
│ 3. コネクション指向 (Connection-Oriented) │
│ - 通信前に接続確立(3ウェイハンドシェイク) │
│ - 通信後に接続終了(4ウェイハンドシェイク) │
│ │
│ 4. フロー制御 (Flow Control) │
│ - 受信側のバッファ溢れを防止 │
│ - ウィンドウサイズによる送信量調整 │
│ │
│ 5. 輻輳制御 (Congestion Control) │
│ - ネットワーク混雑時の送信レート調整 │
│ - スロースタート、輻輳回避アルゴリズム │
│ │
│ 6. 全二重通信 (Full Duplex) │
│ - 双方向同時通信が可能 │
│ │
└─────────────────────────────────────────────────────────────┘
2.2 TCPヘッダの構造
┌─────────────────────────────────────────────────────────────┐
│ TCPヘッダ(20〜60バイト) │
├─────────────────────────────────────────────────────────────┤
│ │
│ 0 1 2 3
│ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
│ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
│ | 送信元ポート | 宛先ポート |
│ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
│ | シーケンス番号 |
│ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
│ | 確認応答番号 (ACK番号) |
│ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
│ | データ | |U|A|P|R|S|F| |
│ | オフセット| 予約 |R|C|S|S|Y|I| ウィンドウサイズ |
│ | | |G|K|H|T|N|N| |
│ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
│ | チェックサム | 緊急ポインタ |
│ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
│ | オプション(可変長) |
│ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
│ │
│ 主要フラグ: │
│ - SYN: 接続開始 │
│ - ACK: 確認応答 │
│ - FIN: 接続終了 │
│ - RST: 接続リセット │
│ - PSH: プッシュ(バッファリングせず即座に転送) │
│ - URG: 緊急データ │
│ │
└─────────────────────────────────────────────────────────────┘
3. TCP接続の確立と終了
3.1 3ウェイハンドシェイク(接続確立)
┌─────────────────────────────────────────────────────────────┐
│ 3ウェイハンドシェイク │
├─────────────────────────────────────────────────────────────┤
│ │
│ クライアント サーバー │
│ │ │ │
│ │ │ [LISTEN] │
│ │ │ │
│ Step 1 │ ──────── SYN (seq=x) ─────────► │ │
│ │ │ │
│ [SYN_SENT] │ [SYN_RECEIVED] │
│ │ │ │
│ Step 2 │ ◄─── SYN+ACK (seq=y, ack=x+1) ── │ │
│ │ │ │
│ │ │ │
│ Step 3 │ ──────── ACK (ack=y+1) ────────► │ │
│ │ │ │
│ [ESTABLISHED] │ [ESTABLISHED] │
│ │ │ │
│ │ 双方向通信可能 │ │
│ │ ◄────────────────────────────► │ │
│ │
│ ───────────────────────────────────────────────────────── │
│ │
│ 各ステップの意味: │
│ │
│ 1. SYN: クライアント→サーバー │
│ 「接続したい。私のシーケンス番号はxから始める」 │
│ │
│ 2. SYN+ACK: サーバー→クライアント │
│ 「OK。私のシーケンス番号はyから始める。x+1を待っている」 │
│ │
│ 3. ACK: クライアント→サーバー │
│ 「了解。y+1を待っている」 │
│ │
└─────────────────────────────────────────────────────────────┘
3.2 4ウェイハンドシェイク(接続終了)
┌─────────────────────────────────────────────────────────────┐
│ 4ウェイハンドシェイク │
├─────────────────────────────────────────────────────────────┤
│ │
│ クライアント サーバー │
│ │ │ │
│ [ESTABLISHED] │ [ESTABLISHED] │
│ │ │ │
│ Step 1 │ ──────── FIN (seq=x) ─────────► │ │
│ │ │ │
│ [FIN_WAIT_1] │ [CLOSE_WAIT] │
│ │ │ │
│ Step 2 │ ◄─────── ACK (ack=x+1) ───────── │ │
│ │ │ │
│ [FIN_WAIT_2] │ │
│ │ │ │
│ │ (サーバーが残りのデータを送信)│ │
│ │ │ │
│ Step 3 │ ◄─────── FIN (seq=y) ────────── │ │
│ │ │ │
│ [TIME_WAIT] │ [LAST_ACK] │
│ │ │ │
│ Step 4 │ ──────── ACK (ack=y+1) ────────► │ │
│ │ │ │
│ │ │ [CLOSED] │
│ │ │ │
│ (2MSL待機) │ │
│ │ │ │
│ [CLOSED]│ │ │
│ │
│ ─────────── ────────────────────────────────────────────── │
│ │
│ なぜ4ステップ必要なのか: │
│ - TCP は全二重通信のため、各方向を独立して終了する必要 │
│ - クライアント→サーバー方向の終了 (Step 1-2) │
│ - サーバー→クライアント方向の終了 (Step 3-4) │
│ │
└─────────────────────────────────────────────────────────────┘
3.3 TCP状態遷移
┌─────────────────────────────────────────────────────────────┐
│ 主要なTCP状態 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 【接続前】 │
│ CLOSED - 初期状態 │
│ LISTEN - サーバーが接続待ち │
│ │
│ 【接続確立中】 │
│ SYN_SENT - クライアントがSYN送信後 │
│ SYN_RECEIVED - サーバーがSYN受信後 │
│ │
│ 【接続確立後】 │
│ ESTABLISHED - 接続確立済み、データ送受信可能 │
│ │
│ 【接続終了中(アクティブクローズ側)】 │
│ FIN_WAIT_1 - FIN送信後、ACK待ち │
│ FIN_WAIT_2 - ACK受信後、相手のFIN待ち │
│ TIME_WAIT - 最後のACK送信後、2MSL待機 │
│ │
│ 【接続終了中(パッシブクローズ側)】 │
│ CLOSE_WAIT - FIN受信後、アプリ終了待ち │
│ LAST_ACK - FIN送信後、最後のACK待ち │
│ │
│ 【同時クローズ】 │
│ CLOSING - 両側が同時にFINを送信した場合 │
│ │
└─────────────────────────────────────────────────────────────┘
3.4 TIME_WAITの重要性
┌─────────────────────────────────────────────────────────────┐
│ TIME_WAIT状態の役割 │
├─────────────────────────────────────────────────────────────┤
│ │
│ TIME_WAIT: 接続を閉じた後、2×MSL(Maximum Segment Lifetime)│
│ の間、その接続の情報を保持する状態 │
│ │
│ MSL: 通常30秒〜2分(Linux デフォルト: 60秒) │
│ → TIME_WAIT は 2×60秒 = 120秒 = 2分 │
│ │
│ ───────────────────────────────────────────────────────── │
│ │
│ 【なぜTIME_WAITが必要か】 │
│ │
│ 1. 遅延パケットの処理 │
│ - ネットワーク上に残っている古いパケットが │
│ 新しい接続に誤って届くことを防ぐ │
│ │
│ 2. 最後のACKの再送 │
│ - 最後のACKが失われた場合、相手がFINを再送する │
│ - TIME_WAIT中なら再度ACKを返せる │
│ │
│ ───────────────────────────────────────────────────────── │
│ │
│ 【TIME_WAITが問題になるケース】 │
│ │
│ 高トラフィックサーバーで大量のTIME_WAIT接続が滞留 │
│ → ポート枯渇、メモリ消費 │
│ │
│ 確認コマンド: │
│ $ netstat -an | grep TIME_WAIT | wc -l │
│ $ ss -s | grep timewait │
│ │
└─────────────────────────────────────────────────────────────┘
4. ポート番号とソケット
4.1 ポート番号の概念
┌─────────────────────────────────────────────────────────────┐
│ ポート番号 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ポート番号: 0 〜 65535 (16ビット) │
│ │
│ 【ポート番号の分類】 │
│ │
│ ┌──────────────┬──────────────┬─────────────── ──────────┐ │
│ │ 範囲 │ 名称 │ 用途 │ │
│ ├──────────────┼──────────────┼─────────────────────────┤ │
│ │ 0 - 1023 │ Well-known │ 標準的なサービス │ │
│ │ │ ポート │ (HTTP:80, HTTPS:443等) │ │
│ │ │ │ root権限が必要(Unix) │ │
│ ├──────────────┼──────────────┼─────────────────────────┤ │
│ │ 1024 - 49151 │ Registered │ IANA登録済みサービス │ │
│ │ │ ポート │ (MySQL:3306等) │ │
│ ├──────────────┼──────────────┼─────────────────────────┤ │
│ │ 49152 - 65535│ Dynamic/ │ クライアント側の │ │
│ │ │ Ephemeral │ 動的ポート │ │
│ │ │ ポート │ (OSが自動割当) │ │
│ └──────────────┴──────────────┴─────────────────────────┘ │
│ │
│ 【主要なWell-knownポート】 │
│ │
│ 20/21 FTP (データ/制御) │
│ 22 SSH │
│ 23 Telnet │
│ 25 SMTP │
│ 53 DNS (TCP/UDP) │
│ 80 HTTP │
│ 110 POP3 │
│ 143 IMAP │
│ 443 HTTPS │
│ 3306 MySQL │
│ 5432 PostgreSQL │
│ 6379 Redis │
│ 8080 HTTP代替(アプリサーバー) │
│ │
└─────────────────────────────────────────────────────────────┘
4.2 ソケット
┌─────────────────────────────────────────────────────────────┐
│ ソケットとコネクション │
├─────────────────────────────────────────────────────────────┤
│ │
│ 【ソケットとは】 │
│ - ネットワーク通信のエンドポイント │
│ - IPアドレス + ポート番号 の組み合わせ │
│ │
│ 例: 192.168.1.10:8080 (ソケット) │
│ │
│ ───────────────────────────────────────────────────────── │
│ │
│ 【TCP接続の一意性】 │
│ │
│ TCP接続は以下の5つ組(5-tuple)で一意に識別される: │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ (送信元IP, 送信元ポート, 宛先IP, 宛先ポート, TCP) │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 例: │
│ (192.168.1.10, 52340, 93.184.216.34, 443, TCP) │
│ (192.168.1.10, 52341, 93.184.216.34, 443, TCP) │
│ ↑ 送信元ポートが異なるので別の接続 │
│ │
│ ───────────────────────────────────────────────────────── │
│ │
│ 【サーバー側のソケット】 │
│ │
│ サーバー (0.0.0.0:8080 LISTEN) │
│ │ │
│ ├── 接続1: (Client1_IP:52340, Server_IP:8080) │
│ ├── 接続2: (Client1_IP:52341, Server_IP:8080) │
│ ├── 接続3: (Client2_IP:49200, Server_IP:8080) │
│ └── ... │
│ │
│ → 1つのLISTENソケットで複数のクライアント接続を処理 │
│ │
└─────────────────────────────────────────────────────────────┘
5. TCPとUDPの比較
5.1 特徴の比較
┌─────────────────────────────────────────────────────────────┐
│ TCP vs UDP │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌────────────────────┬────────────────┬────────────────┐ │
│ │ 特徴 │ TCP │ UDP │ │
│ ├────────────────────┼────────────────┼────────────────┤ │
│ │ 接続 │ コネクション型 │ コネクションレス │ │
│ │ 信頼性 │ あり(再送) │ なし │ │
│ │ 順序保証 │ あり │ なし │ │
│ │ フロー/輻輳制御 │ あり │ なし │ │
│ │ ヘッダサイズ │ 20-60バイト │ 8バイト │ │
│ │ オーバーヘッド │ 大きい │ 小さい │ │
│ │ 速度 │ 相対的に遅い │ 相対的に速い │ │
│ │ 通信形態 │ 1対1 │ 1対1, 1対多 │ │
│ │ ブロードキャスト │ 不可 │ 可能 │ │
│ └────────────────────┴────────────────┴────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘