ネットワーク通信において、TCPの挙動を「見える化」するには、適切なツールと環境構築が不可欠です。本稿では、パケットの損失、順序乱れ、再送制御、フロー制御といったTCPの核心機能を、実際にキャプチャしたデータで明確に解説します。
目に見えないパケットを可視化する
ネットワーク上のデータ交換は通常、肉眼では確認できません。この抽象性がコンピュータネットワーク学習の障壁となります。しかし、tcpdump と Wireshark の2つのツールを使えば、不可視だった通信が視覚的に把握可能になります。
- tcpdump:Linuxサーバー向けのコマンドラインツール。特定条件でパケットを収集し、pcap形式で保存。
- Wireshark:GUIベースの解析ツール。保存されたpcapファイルを開き、プロトコルごとに色分けして詳細なレイヤー情報を表示。
例として、ICMPのping通信をキャプチャする場合:
$ tcpdump -i eth0 icmp and host 183.232.231.174 -w ping.pcap
上記コマンドで取得したファイルをWiresharkで開くと、データリンク層からIP層、ICMP層までの各ヘッダ情報が階層的に表示されます。これにより、MACアドレス、TTL、ICMPタイプなどの詳細を即座に確認できます。
HTTP通信におけるTCPハンドシェイクの観察
HTTP通信を例に、TCPの3ウェイハンドシェイクと4ウェイ切断を観察します。
$ tcpdump -i eth0 host 192.168.3.200 -w http.pcap
$ curl http://192.168.3.200
Wiresharkでhttp.pcapを開くと、最初の3パケットがSYN → SYN-ACK → ACKのハンドシェイク、最後の3パケットがFINによる切断処理です。統計メニューの「フローグラフ」を使うと、時系列で通信フローを視覚化できます。
なお、ウィザードのデフォルト設定では相対シーケンス番号が表示されますが、「プロトコル設定」→「TCP」→「Relative sequence numbers」を無効にすると、実際のランダムな初期シーケンス値を確認できます。
異常ケースの実験:SYNパケット消失時の挙動
仮想マシン2台(クライアント: 192.168.12.37, サーバー: 192.168.12.36)を使用し、以下の3つの異常ケースを検証しました。
ケース1:最初のSYNパケットが消失
サーバーのネットワークケーブルを抜いた状態でcurlを実行。クライアントはSYNパケットを5回まで指数バックオフ(1s, 3s, 7s, 15s, 31s)で再送。最大再送回数は/proc/sys/net/ipv4/tcp_syn_retriesで制御されます。
ケース2:SYN-ACKパケットが消失
クライアント側でiptablesによりサーバーからの応答を破棄:
$ iptables -A INPUT -s 192.168.12.36 -j DROP
このとき、クライアントはSYNを再送し、サーバーもSYN-ACKを再送(最大5回)。再送上限はtcp_synack_retriesで設定可能です。
ケース3:最終ACKパケットが消失
サーバー側でACKパケットを破棄:
$ iptables -A INPUT -p tcp --tcp-flags ACK ACK -j DROP
サーバーはSYN-ACKを5回再送後、接続を破棄。一方クライアントはESTABLISHED状態のまま維持され、データ送信時に最大15回(tcp_retries2)再送を試みた後に切断されます。
TCP Fast Openによる高速接続
Linux 3.7以降では、TCP Fast Open(TFO)が利用可能です。初回接続時にサーバーがCookieを発行し、次回以降はSYNパケットにCookieを含めて送信することで、ハンドシェイク完了前にデータ転送が可能になります。
$ sysctl -w net.ipv4.tcp_fastopen=3
値の意味:
0 = 無効、1 = クライアント有効、2 = サーバー有効、3 = 両方有効
高速再送とSACK
受信側が順序違いのパケットを受信すると、同じACKを繰り返し送信します。送信側は同一ACKを3回受信すると、そのパケットを即時再送(高速再送)します。SACK(Selective Acknowledgment)が有効であれば、欠落部分のみを再送可能で効率的です。
$ sysctl -w net.ipv4.tcp_sack=1
フロー制御とゼロウィンドウ
受信バッファが満杯になると、受信ウィンドウサイズが0(ゼロウィンドウ)を通知します。送信側は定期的に「ウィンドウプローブ」パケットを送信し、ウィンドウ復活を確認します。プローブ間隔は3.4秒 → 6.8秒 → 13.5秒と倍増します。
Nagleアルゴリズムと遅延ACKの干渉
小規模データの送信を抑えるNagleアルゴリズムと、ACKをまとめて送る遅延ACKが同時に有効だと、最大200msの待ち時間が発生します。リアルタイム性が必要なアプリ(SSHなど)では、以下のように無効化すべきです。
// Nagle無効化
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag));
// 遅延ACK無効化
setsockopt(sock, IPPROTO_TCP, TCP_QUICKACK, &flag, sizeof(flag));