Featured image of post TCPとUDPとは?信頼性と速度のトレードオフをやさしく解説【第29回】

TCPとUDPとは?信頼性と速度のトレードオフをやさしく解説【第29回】

この記事でわかること

  • 3ウェイハンドシェイクで接続を確立する仕組みと「3回」が必要な理由
  • シーケンス番号とACKによってデータの欠損・順序崩れを防ぐ仕組み
  • フロー制御(ウィンドウ)がなぜ必要なのか
  • 接続を終了する4ウェイ(FIN)の流れ
  • UDPがこれらをすべて省いても成り立つ理由
  • 信頼性と速度のトレードオフをどう使い分けるか

はじめに

前回までの記事で、TCPは「信頼性重視」、UDPは「速度重視」と学びました。でも「なぜTCPは信頼性を保証できるのか」「UDPは何を省いているのか」という中身はまだ見ていません。

TCPには信頼性を保証するためのいくつかの仕組みが組み込まれています。それぞれが「確実に届ける」ための役割を持っている一方で、通信のオーバーヘッドにもなっています。UDPはそのすべてを省くことで速さを手に入れました。

この「何を得て、何を捨てるか」というトレードオフが今回のテーマです。


TCPとUDPの根本的な違い

一言で表すと、こうなります。

  • TCP:送る前に相手と合意し、届いたか確認しながら送る
  • UDP:確認なし、送りっぱなし

電話とポスティングの違いに近いです。電話は相手が出るまで待ち、話しながら相手の反応を確認します。チラシのポスティングはポストに入れて終わりで、届いたかどうか確認しません。どちらが優れているかではなく、用途が違います。

TCPがどうやって「確認しながら送る」を実現しているか、ひとつひとつ見ていきます。


TCP① 接続の確立——3ウェイハンドシェイク

TCPはデータを送る前に、まず「これから通信します」という合意を相手と交わします。この事前確認の手順を**スリーウェイハンドシェイク(3-way handshake)**と呼びます。

  • Handshake(ハンドシェイク):Hand(手)+ Shake(振る)→「握手」という意味。互いに手を取り合う確認の動作です

「3回」やりとりが必要な理由を見てみましょう。電話をかける場面に例えます。

【1回目】SYN(シン)
クライアント → 「もしもし、聞こえますか?」 → サーバー
  • SYN:Synchronize(シンクロナイズ)→「同期する」「タイミングを合わせる」という意味
  • クライアントが「通信を始めたい」と伝える最初のメッセージ
【2回目】SYN-ACK
クライアント ← 「はい、聞こえています。そちらは聞こえますか?」 ← サーバー
  • サーバーが「あなたの声は聞こえた(ACK)。私の声も聞こえるか確認したい(SYN)」と返す
  • 1つのパケットで2つの意味を持つため SYN-ACK と呼ぶ
【3回目】ACK
クライアント → 「はい、聞こえています。では始めましょう。」 → サーバー
  • ACK:Acknowledge(アクノレッジ)→「受け取ったことを確認する」「認める」という意味
  • クライアントが「サーバーの声も聞こえた」と確認し、これで双方向の通信が確認された

この3回のやりとりで「クライアントからサーバーへの通信」と「サーバーからクライアントへの通信」の両方が問題ないことを確認します。2回では片方向しか確認できないため、3回必要なのです。

3ウェイハンドシェイクが完了して初めて、データの転送が始まります。


TCP② データの保証——シーケンス番号とACK

接続が確立したら、いよいよデータを送ります。TCPは「データが欠けていないか」「順序が正しいか」を保証するためにシーケンス番号を使います。

  • Sequence(シーケンス):「順序」「連続した並び」という意味

シーケンス番号は、送るデータに振られる「ページ番号」です。大きなデータを複数のパケットに分けて送るとき、それぞれのパケットに「このデータは何バイト目から始まる」という番号を付けます。

送信側:
  パケット① シーケンス番号:1    データ: 1〜500バイト目
  パケット② シーケンス番号:501  データ: 501〜1000バイト目
  パケット③ シーケンス番号:1001 データ: 1001〜1500バイト目

受信側は受け取るたびに「次はここから欲しい」という番号を ACK(確認応答)として返します。

受信側:
  「パケット①受け取った。501番から送って」 → ACK 501
  「パケット②受け取った。1001番から送って」 → ACK 1001
  「パケット③受け取った。1501番から送って」 → ACK 1501

パケットが届かなかったとき——再送制御

送信側は ACK が一定時間内に返ってこなければ「届かなかった」と判断し、同じパケットを再送します。これを**再送制御(Retransmission)**と呼びます。

  • Retransmission(リトランスミッション):Re(再び)+ Transmission(伝送)→「再送信」という意味
パケット②が途中で消えた場合:

送信側:パケット② → ×(消失)→ サーバー
        (ACK 1001 が返ってこない)
        (タイムアウト後)
送信側:パケット② → 再送 → サーバー
                            ↓
                       ACK 1001 を返す

パケットが順序バラバラで届いたとき

ネットワークの経路によっては、後から送ったパケットが先に届くことがあります。シーケンス番号があれば、受信側で「2→4→1→3」の順に届いても「1→2→3→4」に並べ直してからアプリに渡せます。

ページ番号のついた原稿がバラバラに届いても、番号順に並べ直せるのと同じです。


TCP③ 受信側を守る——フロー制御

データを受け取るにも限界があります。受信側の処理が追いつかないまま送り続けると、受け取れないデータが溢れてしまいます。

これを防ぐのが**フロー制御(Flow Control)**です。受信側が「今はこれだけしか受け取れない」と送信側に伝え、送信量を調整します。

  • Flow(フロー):「流れ」という意味。データの流れの量を制御する仕組みです

具体的には**ウィンドウサイズ(Window Size)**という値を使います。

  • Window(ウィンドウ):「窓」という意味。「今受け取れるデータの枠」を窓の大きさに例えています
受信側:「今は1000バイトまで受け取れます(ウィンドウサイズ=1000)」
送信側:1000バイト分を送る
受信側:「処理が追いついた。また1000バイト受け取れます」
送信側:次の1000バイトを送る

受信側の処理が重くなれば「今は200バイトしか受け取れません」と通知し、送信側が量を減らします。受信側が余裕を取り戻せば枠が広がります。


TCP④ 接続の終了——4ウェイ

電話を切るときも「じゃあ、失礼します」「はい、さようなら」という確認をしますよね。TCPの接続終了も同じです。4回のやりとり(FINハンドシェイク)で正式に接続を閉じます。

  • FIN:Finish(フィニッシュ)→「終了する」「完了する」という意味
【1回目】クライアント → 「私は送り終わりました(FIN)」 → サーバー
【2回目】クライアント ← 「わかりました(ACK)」← サーバー
【3回目】クライアント ← 「私も送り終わりました(FIN)」 ← サーバー
【4回目】クライアント → 「わかりました(ACK)」 → サーバー

「私が送り終わった」と「相手が送り終わった」は別々の出来事なので、それぞれ確認が必要です。そのため4回になります。3ウェイハンドシェイクが「接続の握手」なら、FINハンドシェイクは「接続のお辞儀」です。


TCPのオーバーヘッドをざっくり把握する

ここで一度、TCPの接続から切断までに何回のやりとりが発生するか整理します。

接続確立(3ウェイハンドシェイク):3回
データ転送(ACKのやりとり)       :データ量に比例
接続終了(4ウェイ FIN)           :4回

**RTT(Round Trip Time)**という概念があります。

  • Round(ラウンド):「往復の」という意味
  • Trip(トリップ):「旅」という意味
  • Time(タイム):「時間」

合わせて「パケットが相手に届いて返ってくるまでの往復時間」です。東京—東京間なら1ms未満、東京—ニューヨーク間なら約150msになります。

3ウェイハンドシェイクだけで最低1RTT、データを送り始めてACKが返るまでさらに時間がかかります。TCPの信頼性は「たくさんのやりとり」によって成り立っており、やりとりの回数がそのまま遅延になります。


UDP——すべてを省いた潔い設計

UDPはTCPが備えている仕組みをほぼすべて省いています。

機能 TCP UDP
接続確立(ハンドシェイク) あり なし
ACK・再送制御 あり なし
シーケンス番号・順序保証 あり なし
フロー制御(ウィンドウ) あり なし
ヘッダサイズ 20バイト以上 8バイト

接続確立のやりとりが0回。ACKを待つ必要もない。ヘッダも最小限。その結果、データを受け取った瞬間に送信を始めることができます。

UDPで「届かなくてもいい」場面とは

「届かないとまずいのでは?」と思うかもしれません。でも実は、届かないほうがよい場面があります。

音声通話を例にします。あなたが「おはようございます」と話すとき、最初の「お」が届かなかったとします。TCPなら再送してもらえます。ただし再送されてくる頃には、相手はすでに「ようございます」まで話し終えています。

「お」が届いても、話の流れはすでに先へ進んでいます。今さら0.3秒前の音声を再生すると、現在の音声との間にズレが生じて会話が崩れます。音声通話にとって「正確に全部届くこと」より「今この瞬間のデータが遅れずに届くこと」のほうが重要です。

オンラインゲームも同じです。0.1秒前のキャラクターの位置より、今の位置が知りたい。古い情報を再送されても役に立ちません。

こういった「古くなった情報は不要、鮮度が命」の用途にはUDPが向いています。

UDPで「届かないと困る」場合の対策

DNSはUDPを使いますが、届かなかったらどうするのでしょうか。アプリケーション側でタイムアウトと再試行を実装しています。「パケットが届かなかったら自分でもう一度送る」という処理をアプリ自身が行うのです。UDPはトランスポート層での保証を省く代わりに、必要なアプリが自前で対策を持ちます。


トレードオフの整理——何を得て、何を捨てるか

TCPとUDPの選択は「何を優先するか」の判断です。

TCPを選ぶとき

データが欠けると致命的な用途です。ウェブページが半分だけ表示される、ファイルが途中で壊れる、SSHのコマンドが欠ける——これらは許容できません。多少遅くなってもデータの完全性が最優先です。

  • ウェブ閲覧(HTTP/HTTPS)
  • メール(SMTP / IMAP / POP3)
  • ファイル転送(FTP / SFTP)
  • リモートアクセス(SSH)

UDPを選ぶとき

多少の欠損より低遅延が重要な用途です。リアルタイム性が命で、古いデータを再送されると逆効果になる場面です。

  • 音声通話・ビデオ通話(VoIP / WebRTC)
  • ライブ配信
  • オンラインゲーム
  • DNS(小さな問い合わせ、届かなければすぐ再試行)

UDPの上にTCPの機能を乗せる——QUICとHTTP/3

近年、「UDPの速さを活かしながら、TCPのような信頼性もアプリケーション層で実現する」という新しいプロトコルが普及しています。それが QUIC(クイック) です。

  • QUIC:Quick UDP Internet Connections の略。「素早いUDPインターネット接続」という意味

QUICはUDP上で動作しながら、再送制御・暗号化・多重化といった機能をアプリケーション層で実装しています。TCP+TLSでは接続確立に2〜3回のRTTが必要だったところを、QUICは0〜1RTTに短縮します。

HTTP/3(ウェブの通信プロトコルの最新版)はQUICを基盤として採用しています。YouTubeやGoogleのサービスはすでにHTTP/3を使っており、体感速度の改善に貢献しています。

「TCPかUDPか」という2択は、このように「アプリケーション層で必要な信頼性を実装したUDP」という第3の道へと進化しています。TCPとUDPのトレードオフを理解しているからこそ、QUICがなぜ生まれたかも納得できます。


まとめ

  • TCPは接続確立・ACK・再送制御・シーケンス番号・フロー制御という複数の仕組みで「全データが正確な順序で届く」ことを保証する。その分やりとりが増え、遅延が生まれる
  • 3ウェイハンドシェイク(SYN→SYN-ACK→ACK)でデータ送信前に双方向の通信を確認する。「3回」必要なのは、送信・受信の両方向をそれぞれ確認するため
  • シーケンス番号でデータにページ番号を付け、ACKで届いた場所を確認しながら転送する。タイムアウトになれば再送する
  • **フロー制御(ウィンドウ)**で受信側の処理能力に合わせて送信量を調整する
  • 接続終了は FINハンドシェイク(4回) で行う
  • UDPはこれらをすべて省いたシンプルな設計。0RTTで即座に送信でき、音声通話・ゲーム・ライブ配信など「鮮度が命」の用途に向いている
  • TCPとUDPの選択は「データの完全性」と「リアルタイム性」のどちらを優先するかで決まる
  • 近年はUDP上で信頼性を独自実装したQUICが普及し、HTTP/3の基盤として採用されている