TCPと信頼性 — ロスを隠して「届いたことにする」

IPは「たぶん届く」ベストエフォート。パケットは落ちるし、順番も入れ替わります。その上に乗って「確実に・順番どおり」届いたように見せるのがTCPです。接続を開く3ウェイハンドシェイク、まとめて送るスライディングウィンドウ、落ちたら送り直す再送、届いた順を直す受信バッファ ― 信頼性の4つの仕掛けを動かして見ていきます。

1. コネクションを開く — 3ウェイハンドシェイク

いきなりデータを送りつけるのではなく、TCPはまずお互いに「準備OK」を確認してから通信を始めます。使うのは3通のメッセージ。各自が自分のシーケンス番号(SEQ)の初期値を相手に伝え、相手はそれをACK(確認応答)で「受け取った、次はこの番号ね」と返します。

「1ステップ進める」で1通ずつ、状態(CLOSED→…→ESTABLISHED)が変わる様子を追ってください。

3ウェイハンドシェイク — 接続確立の3通
SYN=「つなぎたい(自分のSEQはこれ)」、SYN+ACK=「いいよ(自分のSEQはこれ、あなたの次はこれ)」、ACK=「よろしく」。ACKの値は相手のSEQ+1になっているのに注目。3通そろうと両側 ESTABLISHED。
POINT — なぜ2回でなく3回? 接続は双方向。クライアント→サーバとサーバ→クライアントの両方向で「SEQを伝え、それをACKで確認する」必要がある。サーバのSYNとACKは1通にまとめられるので、合計は 4 − 1 = 3通で済む。

2. 一度にたくさん送る — スライディングウィンドウ

1通送るたびにACKを待っていたら、往復時間(RTT)ぶん毎回止まって遅すぎます。そこでTCPはACKを待たずに送ってよい量=ウィンドウを決め、その範囲のセグメントをまとめて送信。ACKが返ってきたぶんだけウィンドウが右へスライドし、新しいセグメントを送れます。

ウィンドウサイズを変えて、同時に「飛んでいる」セグメントの数と、ACKが窓を押し出す様子を見てください。

スライディングウィンドウ — ACKが窓を押し出す
上の箱=セグメント列(緑=ACK済み、青枠=窓内で送信可、灰=まだ)。オレンジの丸が下へ=データ、緑の丸が上へ=ACK。窓が大きいほど同時に多く飛ばせ、速くなります。
POINT — ウィンドウは「未確認のまま出せる量」 ウィンドウサイズは、まだACKされていないのに送信を許されるデータ量。大きいほど回線を埋められるが、受信側のバッファ(受信ウィンドウ)と、混雑ぐあい(輻輳ウィンドウ、次のレッスン)で上限が決まる。
最大スループット ≈ ウィンドウサイズ ÷ RTT RTT(往復時間)が長い遠距離ほど、同じ速度を出すには大きな窓が要る(帯域遅延積)

3. 失われたら送り直す — 再送

ネットワークではパケットが落ちます。TCPはACKが返ってこないことを手がかりにロスを検知し、再送します。きっかけは2つ ―(1)一定時間ACKが来ないタイムアウト、(2)後続は届いているのに1つだけ欠けたときに受信側が繰り返す重複ACK。重複ACKが3回続くと、タイムアウトを待たず即座に送り直すファストリトランスミットが発動します。

ロス率を上げて、パケットが途中で消える→タイムアウト→再送、の流れを観察してください。

再送 — ロスをタイムアウトと重複ACKで埋める
赤い✕=ロスしたセグメント。落ちると下のタイムアウトバーが伸び、満ちると紫で再送。欠けている間、あとから届いたぶんはピンクの重複ACKになり、3回で⚡ファストリトランスミットが起きます。
注意 — 「届かない」ではなく「ACKが来ない」で判断する 送信側はパケットが落ちた瞬間を知る術がない。分かるのはACKが返ってこないことだけ。だからタイムアウトは長すぎれば遅く、短すぎれば無駄な再送を生む。TCPはRTTを測って待ち時間を自動調整(RTO)している。

4. バラバラに届いても直す — 順序保証と受信バッファ

パケットは別々の経路を通ったり再送されたりで、送った順とは違う順で届くことがあります。TCPは各セグメントのシーケンス番号を見て、受信側のバッファにいったん並べ、先頭から連続してそろったぶんだけアプリに渡します。欠けている番号があると、後ろがそろっていても待たされます(ヘッドオブラインブロッキング)。

受信バッファ — 順不同で届いても順番どおり渡す
上=送信順(1,2,3,…)、下=受信バッファ。緑=アプリに渡せた連続ぶん、黄=届いたが順番待ち、点線=まだ欠けている番号。チェックを外すと並べ替えなしで、届いた順のまま渡ってしまい順序が壊れます。
POINT — シーケンス番号が「順番」と「重複」を両方解決する 各バイトに通し番号を振るだけで、受信側は並べ替え(番号順に並べる)も重複排除(同じ番号は捨てる)も抜け検出(欠番を見つける)もできる。再送で同じデータが二重に届いても、番号を見れば安全に無視できる。

5. まとめ — 信頼性は4つの仕掛けの合わせ技

一歩先へ — TCP/UDP、そして輻輳制御へ この信頼性はタダではない ― 接続確立の1往復、ACK待ち、順序保証による遅延。だからゲームや音声など「多少落ちても速さ優先」の用途では、これらを省いたUDPが選ばれる。さらにTCPには本レッスンで固定にした「窓の大きさを混雑に応じて伸縮させる」仕組み ― 輻輳制御があり、これが次のレッスンの主役だ。