
TCP と UDP の基本 - 3ウェイハンドシェイクと信頼性の仕組みを理解する
TCP/IP 定番の入門書
通信の全体像を追える一冊
対話形式でやさしい入門
当サイトは Amazon.co.jp を宣伝しリンクすることで紹介料を得る手段を提供する、Amazonアソシエイト・プログラムの参加者です。価格・在庫はリンク先の最新情報をご確認ください。
Web ページを開くとき、動画を再生するとき、オンラインゲームで対戦するとき。これらはどれもインターネット越しの通信ですが、その足元では性格の異なる2つのプロトコルが使い分けられています。TCP(Transmission Control Protocol)とUDP(User Datagram Protocol)です。
この記事では、TCP と UDP の違いを、一次ソースである RFC 9293(TCP、2022年に旧 RFC 793 を置き換えた統合仕様)と RFC 768(UDP)を軸に整理します。TCP の代名詞ともいえる3ウェイハンドシェイク、コネクションの終了と TIME-WAIT、シーケンス番号による信頼性、フロー制御と輻輳制御、そして UDP 上で信頼性を実現する QUIC まで、Web 開発者・インフラ担当者向けに一通り押さえます。
TCP/IP の層と、その中での TCP・UDP の位置づけ
インターネットの通信は、役割ごとに層(レイヤー)を分けて設計されています。ざっくり4つの層で考えると、TCP と UDP がどこにいるのかが見えてきます。
| 層 | 役割 | 代表的なプロトコル |
|---|---|---|
| アプリケーション層 | アプリ固有のやり取り | HTTP、DNS、SMTP |
| トランスポート層 | 端末上のプログラム間で届ける | TCP、UDP |
| インターネット層 | 宛先ホストまで届ける | IP(IPv4 / IPv6) |
| リンク層 | 隣の機器へ物理的に届ける | Ethernet、Wi-Fi |
IP は「ホストからホストへパケットを届ける」ことは担いますが、途中でパケットが失われたり、順序が入れ替わったりする可能性があります。IP 自身は、それを直す責任を持ちません。
そこで登場するのがトランスポート層です。TCP と UDP はどちらもポート番号を使って、1台のホスト上で動く複数のプログラム(Web サーバー、メールサーバーなど)のうち、どれ宛ての通信かを区別します。RFC 9293 も「TCP はポート番号を使ってアプリケーションサービスを識別し、ホスト間の個別のフローを多重化する」と述べています。TCP と UDP の決定的な違いは、この上に信頼性を積むかどうかです。
UDP: 最小限の仕組みで速く送る
まずシンプルな UDP から見ます。UDP は RFC 768(J. Postel、1980年8月)で定義された、非常に小さなプロトコルです。RFC 768 は UDP を「アプリケーションプログラムが最小限のプロトコル機構でメッセージを送るための手続き」と表現しています。
UDP の特徴は、裏を返せば「やらないこと」の多さです。
- コネクションレス: 事前のやり取り(ハンドシェイク)なしに、いきなりデータグラムを送る
- 到達保証なし: RFC 768 は「配送と重複防止は保証されない(delivery and duplicate protection are not guaranteed)」と明記している
- 順序保証なし: 届いた順番が送った順番と一致するとは限らない
- 再送なし・フロー制御なし・輻輳制御なし: 失われても知らせず、送信ペースの調整もしない
そのぶんヘッダは非常に軽量です。UDP のヘッダはわずか8バイトで、4つの16ビットフィールドだけを持ちます。
| フィールド | 内容 |
|---|---|
| 送信元ポート(Source Port) | 応答先のポート。任意(0 も可) |
| 宛先ポート(Destination Port) | 宛先アプリケーションのポート |
| 長さ(Length) | ヘッダ+データの長さ。最小は8オクテット |
| チェックサム(Checksum) | 誤り検出用。IPv4 では任意 |
チェックサムは16ビットの1の補数和で計算し、IPv4 では送っても送らなくてもよい任意項目です。RFC 768 は「送信側がチェックサムを生成しなかった場合は、全ビット0を送る」と定めています。
「保証しない」ことは弱点にも見えますが、速さと軽さという強みでもあります。1往復のハンドシェイクも、再送待ちもないため、遅延に敏感な用途に向きます。DNS の問い合わせ、音声・映像のストリーミング、オンラインゲーム、NTP による時刻同期などが代表例です。DNS が UDP を基本に使う背景は、DNS の仕組み入門 でも触れています。
TCP: 信頼性を積み上げる
一方の TCP は、RFC 9293 の言葉を借りれば「アプリケーションに対して信頼性のある、順序どおりの、バイトストリームサービスを提供する(reliable, in-order, byte-stream service)」プロトコルです。UDP が「送りっぱなし」なのに対し、TCP は次のような仕組みで信頼性を作り込んでいます。
- シーケンス番号: 送るデータの1オクテットごとに番号を振り、順序を管理する
- 確認応答(ACK): 受け取った側が「ここまで受け取った」と返す
- 再送: 一定時間 ACK が返らなければ、送り直す
- フロー制御: 受信側の処理能力を超えないよう、送信量を調整する
- 輻輳制御: ネットワークの混雑に応じて、送信ペースを加減する
確認応答は累積的(cumulative)です。RFC 9293 は「シーケンス番号 X の確認応答は、X より前(X を含まない)のすべてのオクテットを受信したことを示す」と説明しています。つまり ACK 番号は「次に受け取りたいオクテットの番号」を表します。
TCP のヘッダは UDP より豊かで、最小でも20バイトあります。送信元・宛先ポート、シーケンス番号(32ビット)、確認応答番号(32ビット)、データオフセット、各種制御フラグ(SYN、ACK、FIN、RST、PSH、URG など)、ウィンドウ、チェックサム、緊急ポインタなどを持ちます。なお TCP のチェックサムは UDP と違い省略できません。RFC 9293 は「TCP チェックサムは決して任意ではない。送信側は必ず生成し、受信側は必ず検査しなければならない」と明言しています。
NOTE
TCP が扱うのは「メッセージの列」ではなく、切れ目のないバイトストリームです。アプリが send() した区切りは保存されず、受信側では複数の送信がまとまって届いたり(結合)、1回の送信が分割されて届いたりします。メッセージ境界が必要なら、アプリ側のプロトコルで長さやデリミタを決める必要があります。
3ウェイハンドシェイク: コネクションを開く
TCP は通信を始める前に、まず両者でコネクションを確立します。この手順が有名な3ウェイハンドシェイク(3-way handshake、3WHS)です。目的は、RFC 9293 の言葉では「各側が自分の初期シーケンス番号を送り、それが相手から確認応答されるのを受け取る」ことにあります。互いの開始番号をすり合わせる儀式、と考えると分かりやすいです。
流れは次の3段です。
- SYN: クライアントが SYN フラグを立て、自分の初期シーケンス番号
xを送る - SYN-ACK: サーバーが SYN と ACK を同時に立て、自分の初期番号
yを送りつつ、x+1で相手の SYN を確認する - ACK: クライアントが
y+1でサーバーの SYN を確認する
この3往復(正確には2往復半)で、両者は互いの初期シーケンス番号を確認し合い、ESTABLISHED(確立済み)状態に入ります。ここでようやくデータのやり取りが始まります。UDP がハンドシェイクなしにいきなり送るのと対照的に、TCP はこの1往復半のコストを先に払って信頼性の土台を作るわけです。
初期シーケンス番号を毎回0から始めず、ある値から始める理由の1つは、古いコネクションの残存パケットとの混同や、なりすましを避けるためです。RFC 9293 でも初期シーケンス番号の選び方が詳しく規定されています。
コネクションの状態遷移
TCP コネクションは、確立から終了まで状態機械(ステートマシン)として管理されます。RFC 9293 は次の11個の状態を定義しています。
LISTEN、SYN-SENT、SYN-RECEIVED、ESTABLISHED、FIN-WAIT-1、FIN-WAIT-2、CLOSE-WAIT、CLOSING、LAST-ACK、TIME-WAIT、CLOSED です。
サーバーは LISTEN で待ち受け、SYN を受けると SYN-RECEIVED へ移り、ACK を受けて ESTABLISHED に至ります。netstat や ss コマンドでソケットの状態を見ると、これらの名前がそのまま並んでいるのが分かります。
コネクションの終了と TIME-WAIT
コネクションを閉じるときは、FIN(finish)フラグを使います。TCP は全二重(双方向)なので、各方向を独立に閉じます。結果として、開くときの3ウェイに対し、閉じるときは4ウェイになるのが基本形です。
RFC 9293 は「相手側の TCP が FIN を確認応答し、かつ自分の FIN を送り終えたら、最初の TCP はその FIN を ACK できる」と説明しています。片方が FIN を送っても、もう片方はまだデータを送り続けられる(ハーフクローズ)点がポイントです。
終了時に特徴的なのが TIME-WAIT 状態です。能動的に閉じた側は、すぐには CLOSED にならず、しばらく TIME-WAIT にとどまります。RFC 9293 は「コネクションを能動的にクローズした場合、TIME-WAIT 状態に 2×MSL(Maximum Segment Lifetime)の時間だけとどまらなければならない」と定めています。MSL は同 RFC で2分とされているため、2×MSL は理屈上4分です。
NOTE
TIME-WAIT が存在するのは、最後の ACK が失われても相手の FIN 再送に応答できるようにし、さらに古いコネクションの遅延パケットが、同じポート組で開いた新しいコネクションに紛れ込むのを防ぐためです。サーバーで TIME-WAIT が大量に積み上がるのは、多くの接続を能動的に閉じている裏返しでもあります。
フロー制御と輻輳制御
TCP が「相手やネットワークを溢れさせない」ために持つのが、フロー制御と輻輳制御です。似ていますが守る対象が違います。
フロー制御は、受信側の処理能力を超えないようにする仕組みです。TCP ヘッダのウィンドウ(window)フィールドで、受信側が「いまどれだけ受け取れるか」を送信側に伝えます。RFC 9293 はウィンドウを「確認応答フィールドが示すオクテットから始めて、このセグメントの送信者が受け入れる用意があるデータオクテット数」と定義しています。受信側のバッファが埋まればウィンドウは小さくなり、送信側はそのぶんペースを落とします。ウィンドウ値は符号なしとして扱う必要がある、とも規定されています。
輻輳制御は、受信側ではなくネットワーク全体の混雑を避ける仕組みです。こちらは TCP のヘッダに直接のフィールドがあるわけではなく、送信側が内部に輻輳ウィンドウを持ってペースを加減します。代表的なアルゴリズムは RFC 5681(2009年)にまとまっており、次の4つが柱です。
- スロースタート: 最初は小さく送り、ACK が返るたびに送信量を指数的に増やす
- 輻輳回避: ある閾値を超えたら、増やし方を緩やかにする
- ファストリトランスミット: 重複 ACK を手がかりに、タイムアウトを待たず素早く再送する
- ファストリカバリ: 再送後、送信量をゼロに戻さず控えめに回復する
実際の送信量は「フロー制御のウィンドウ」と「輻輳ウィンドウ」の小さいほうで決まります。受信側の余裕とネットワークの余裕、どちらか厳しいほうに合わせる、というわけです。この「混雑に応じて流量を絞る」考え方は、アプリ層で流量を制限するレート制限アルゴリズム とも通じるものがあります。
TCP と UDP の使い分け
ここまでの違いを表で整理します。
| 観点 | TCP | UDP |
|---|---|---|
| コネクション | あり(3ウェイハンドシェイク) | なし(送りっぱなし) |
| 到達保証 | あり(ACK と再送) | なし |
| 順序保証 | あり | なし |
| フロー制御・輻輳制御 | あり | なし |
| ヘッダサイズ | 最小20バイト | 8バイト |
| 速度・遅延 | 相対的に重い | 軽い・低遅延 |
| 主な定義 | RFC 9293 | RFC 768 |
| 向く用途 | Web、メール、ファイル転送 | DNS、音声・映像、ゲーム、NTP |
選ぶ基準はシンプルです。データが欠けたり順序が乱れたりして困るなら TCP、多少欠けても速さや低遅延が優先なら UDP、が出発点です。Web で使う代表的なポート番号も押さえておくと、実務で役立ちます。
| プロトコル | ポート | トランスポート |
|---|---|---|
| HTTP | 80 | TCP |
| HTTPS | 443 | TCP(HTTP/3 は UDP) |
| SSH | 22 | TCP |
| DNS | 53 | UDP / TCP |
| NTP | 123 | UDP |
QUIC: UDP の上に信頼性を作り直す
「TCP は信頼性、UDP は速さ」という対比は基本ですが、近年はその境界を塗り替える動きがあります。それが QUIC です。QUIC は RFC 9000(2021年)で標準化された「UDP ベースの多重化された安全なトランスポート(A UDP-Based Multiplexed and Secure Transport)」です。
一見すると矛盾して見えます。信頼性のない UDP の上に、なぜ信頼性を載せるのでしょうか。理由は、TCP がカーネルや中継機器に深く根付いていて改良しづらい一方、UDP の上ならアプリケーション側で自由に新しい輸送方式を作れるからです。QUIC は UDP を土台にしつつ、TCP に相当する再送や順序保証、フロー制御を自前で実装します。
QUIC の特徴は次のとおりです。
- 低遅延な接続確立: TLS 1.3 の暗号ネゴシエーションをハンドシェイクに統合し、接続開始を速くする
- ストリーム多重化とヘッドオブラインブロッキングの回避: 複数ストリームを並行して流し、片方のパケット損失が他方をブロックしない
- 標準で暗号化: 通信の秘匿性・完全性を組み込みで備える
TCP では、1本のコネクション上で複数のリクエストを多重化すると、途中の1パケット損失が後続すべてを止めてしまう問題(ヘッドオブラインブロッキング)がありました。QUIC はストリームごとに独立に扱うことでこれを解消します。この QUIC の上で動くのが HTTP/3 で、HTTPS が UDP の443番ポートを使う場面が増えているのは、この流れによるものです。ブラウザとサーバー間のリアルタイム通信の選択肢を整理したWebSocket / SSE / ポーリングの比較 も、あわせて読むと通信レイヤーの見取り図がつかめます。
まとめ
- トランスポート層には性格の異なる2つがある。TCP(RFC 9293)は信頼性・順序保証あり、UDP(RFC 768)は軽量・低遅延で保証なし。どちらもポート番号でアプリを多重化する
- TCP は3ウェイハンドシェイク(SYN / SYN-ACK / ACK)で互いの初期シーケンス番号を確認し合い、ESTABLISHED になってから通信する
- 信頼性はシーケンス番号・累積 ACK・再送で作る。終了は FIN による4ウェイで、能動クローズ側はTIME-WAIT(2×MSL)にとどまる
- 流量はフロー制御(ウィンドウ)と輻輳制御(RFC 5681)の小さいほうで決まる。前者は受信側、後者はネットワークの混雑を守る
- UDP の上に信頼性と多重化を作り直したのが QUIC(RFC 9000)。HTTP/3 の土台として、Web の通信を静かに置き換えつつある
TCP と UDP の違いは、突き詰めれば「信頼性のコストを、いつ・誰が払うか」の設計判断です。この土台が分かると、DNS がなぜ UDP なのか、HTTP/3 がなぜ UDP に戻ったのか、といった一段上の話も自然につながって見えてきます。


