概要
※ その2があるかは分かりません
突然ですが、「TCP/IPを説明してください」と言われて、パッと答えられますか?
正確に答えられるか、というと怪しい方もいるのではないでしょうか。
AIがコードを書いてくれる時代だからこそ、「AIの出力が正しいか判断する基礎知識」の価値はむしろ上がっていると感じます。この記事では、TCP/IPの基本から、UDPとの違い・使い分けまでを、実例つきで整理します。
TCP/IPとは
まず名前の整理からいきます。
TCP/IPは、インターネットで使われる通信プロトコル群(プロトコルスイート)の総称です。代表的な TCP(Transmission Control Protocol)と IP(Internet Protocol)の2つが名前になっていますが、実際にはHTTPやDNS、UDPなども含んでいます。
TCP/IPでは、通信の役割を4つの階層に分けて考えます。
| 階層 | 役割 | 代表的なプロトコル |
|---|---|---|
| アプリケーション層 | アプリ同士の会話の中身 | HTTP, HTTPS, DNS, SMTP |
| トランスポート層 | 通信の品質管理(今回の主役) | TCP, UDP |
| インターネット層 | 宛先までの配送 | IP |
| ネットワークインターフェース層 | 物理的な伝送 | Ethernet, Wi-Fi |
ちなみに「OSI参照モデル(7階層)」は、「通信機能はこう分割すべき」という理論から設計したより詳細に分割された参照用のモデルです。
実際のインターネットはこのTCP/IP 4階層モデルで動いています。「OSIは設計図の理想形、TCP/IPは現実に建った建物」くらいの認識でOKです。
荷物の配送に例えると
- IP: 住所(IPアドレス)を頼りに荷物を届ける配送業者。ただしベストエフォートなので、荷物が途中で紛失しても、順番が入れ替わっても関知しない
- TCP: その配送業者を使いつつ、「届いたか確認の連絡をする」「届いてなければ再送する」「荷物を順番通りに並べ直す」までやってくれる丁寧な窓口
- UDP: 確認なしでとにかく投げ続ける窓口。速いが、届いたかは知らない
IPだけだと「届くかわからない配送」なので、その上に乗るTCPやUDPが通信の品質を決めている、という関係です。
TCPを"完全に理解"する
TCPの仕事を一言でいうと、「信頼できない配送(IP)の上に、信頼できる通信を作ること」です。
具体的には以下を保証してくれます。
- 接続の確立: 通信の前に相手と合意を取る(3ウェイハンドシェイク)
- 到達保証: 届かなかったデータは再送する
- 順序保証: データを送った順番通りに並べ直す
- 輻輳制御: ネットワークが混んでいたら送る量を自動で調整する
3ウェイハンドシェイク
TCPは通信を始める前に、3回のやり取りで「お互い通信できる状態だよね?」を確認します。
このやり取りがあるおかげで、「相手がいないのにデータを送り続ける」事故を防げます。逆にいうと、通信開始前に必ず1往復半のラリーが発生するので、その分の遅延コストがかかります。ここが、後述するUDPとの比較で重要となります。
到達保証と順序保証
TCPは送るデータにシーケンス番号を振り、受け取った側は「ここまで受け取ったよ」という確認応答を返します。
- 確認応答が返ってこない → 「届いてないな」と判断して再送
- 順番が入れ替わって届いた → シーケンス番号を見て並べ直す
この仕組みのおかげで、アプリケーション側は「データが欠けてないか」「順番が合っているか」を一切気にせず開発できます。普段僕たちがAPI開発でパケットロスを意識しなくていいのは、TCPが下で全部やってくれているからなんですね。
実は毎日使っているTCP
「TCPなんて意識したことない」という人も、実務ではほぼ確実に使っています。
| 日常の操作 | 裏で動いているもの |
|---|---|
| APIを叩く / Webを見る | HTTP/HTTPS(TCP 80/443番ポート) |
| MySQLに接続する | TCP 3306番ポート |
| SSHでサーバーに入る | TCP 22番ポート |
| gRPCでマイクロサービス間通信 | HTTP/2(TCP上) |
| WebSocketでリアルタイム通信 | TCP上でプロトコルアップグレード |
たとえばGoでDBやAPIに接続するとき、こんなコードを見たことがあると思います。
// "tcp" と明示的に書いている ← 実はここでTCPを選んでいる
conn, err := net.Dial("tcp", "example.com:443")
if err != nil {
log.Fatal(err)
}
defer conn.Close()
net.Dial("tcp", ...) の第一引数はまさに「トランスポート層のプロトコルとしてTCPを使う」という指定です。この1行の指定によって、裏側では3ウェイハンドシェイクが走っています。
curl -v でAPIを叩いたときに出てくるこの行もTCPです。
* Connected to example.com (93.184.216.34) port 443
この「Connected」が表示された時点で、3ウェイハンドシェイクが完了しています。
UDPとの違い、使い分けは?
さて、トランスポート層にはTCPとは別にUDP(User Datagram Protocol)があります。
UDPの仕事を一言でいうと、「何も保証しない代わりに、とにかく速く送ること」です。
| 観点 | TCP | UDP |
|---|---|---|
| 接続確立 | 必要(3ウェイハンドシェイク) | 不要(いきなり送る) |
| 到達保証 | あり(再送してくれる) | なし(届かなくても知らない) |
| 順序保証 | あり | なし |
| 輻輳制御 | あり | なし |
| 遅延 | 相対的に大きい | 小さい |
| 主な用途 | Web, API, DB, メール | 音声/映像通話, ゲーム, DNS, 動画配信 |
一見すると常にTCPを使う方が到達保証があって良さそうな気がします。
しかし、TCPの再送・順序保証は、裏を返すと「1つのパケットが遅れると、後続のデータ全体が待たされる」ことを意味します。ここで使い分けの軸が見えてきます。
- データが1バイトでも欠けたら困る → TCP(決済、API、DB、ファイル転送)
- 多少欠けてもいいから"今"届いてほしい → UDP(通話、ライブ配信、ゲーム)
ボイスチャットを想像してください。0.5秒前の音声パケットが途中で失われたとして、TCP的に律儀に再送してもらっても、その音声はもう過去のものです。再送を待って音声全体が遅延するくらいなら、一瞬「プツッ」とノイズが入るほうがマシですよね。これがUDPを選ぶ理由です。
UDPの実例: Nintendo Switch 2 の「ゲームチャット」
「多少欠けてもいいから今届いてほしい」の実例として、ニンテンドーシステムズがAWS Summitで発表したNintendo Switch 2 の ゲームチャットを見てみます。
ゲームチャットは、Switch 2のCボタンから起動できる、フレンドとのボイスチャット・ビデオチャット・ゲーム画面共有機能です。資料によると、サービス要件は以下でした。
- 映像、音声のリアルタイム通信ができること
- グループごとに最大12人接続可能であること
- プレイ中のゲームと並行して動作可能であること
- クライアント負荷が小さいこと
- 通信対戦ゲームとも併用できるよう通信帯域を圧迫しないこと
この要件に対して採用されたのが WebRTC で、資料でも通信方式として UDPパケット通信 であることが明記されています。
まさに先ほどの使い分けの話そのままで、
- ボイチャの音声が0.1秒欠けても会話は成立する(到達保証はいらない)
- でも音声が遅延したら会話にならない(低遅延は絶対条件)
- しかも裏で通信対戦ゲームが動いている(TCPの再送や輻輳制御で帯域を食い合いたくない)
という、UDPを選ぶべき条件が全部揃っているケースです。
ちなみにこの資料、WebRTCの接続方式としてP2P(クライアント同士の直接通信)ではなくSFU(Selective Forwarding Unit: サーバー経由でストリームを転送する方式)を採用した理由も載っています。P2P方式は最も遅延が小さい一方、12人グループだと各クライアントのストリーム数とエンコード/デコード数が膨らんでしまう。ゲームと並行動作するためにクライアント負荷を抑えたい、という要件からSFUを選んだそうです。
TCPの実例: Slack のリアルタイムメッセージング
一方の「1バイトでも欠けたら困る」代表として、Slack を見てみます。
出典: Real-time Messaging | Engineering at Slack
Every Slack client has a persistent websocket connection to Slack’s servers to receive real-time events to maintain its state.
Slackのクライアントは、サーバーとWebSocketの持続的な接続を張ってリアルタイムにメッセージを受信しています。WebSocketはTCPの上に成り立つプロトコルなので、これはTCPの実例です。Slackのエンジニアリングブログによると、ピーク時には500万以上の同時WebSocketセッションを維持し、世界中にメッセージを500ms以内に届けているそうです。
ここで面白いのは、SlackもゲームチャットもどちらもWebSocketやWebRTCといった「リアルタイム系」の技術なのに、トランスポート層の選択が真逆なことです。
| Slack(TCP) | ゲームチャット(UDP) | |
|---|---|---|
| 届けるもの | テキストメッセージ | 音声・映像ストリーム |
| 1件欠けたら | 業務連絡が消える(致命的) | 一瞬ノイズが入る(許容できる) |
| 順番が入れ替わったら | 会話が破綻する | 古いフレームは捨てればいい |
| 求める「リアルタイム」 | 数百ms以内に確実に届く | 今この瞬間の音声が届く |
「上司からの『そのデプロイ待って』が欠落する」ことは許されないので、Slackのメッセージは到達保証・順序保証のあるTCPの上に乗せる。一方、音声フレームは鮮度が命なのでUDP。同じ"リアルタイム"でも、何を犠牲にできるかで選ぶプロトコルの選択が変わっています。
QUICとは
最近のWebでは QUIC(HTTP/3の土台となるプロトコル)の採用が進んでいます。QUICは面白いことに、UDPの上に、再送や順序保証といったTCP的な信頼性を自前で再実装したトランスポート層の通信プロトコルです。
出典: How Facebook is bringing QUIC to billions - Engineering at Meta
Meta(Facebook)は自社トラフィックの75%以上をQUIC + HTTP/3に移行し、HTTP/2(TCP)と比較してリクエストエラー6%減、テールレイテンシー20%減という結果を報告しています。
※facebookのログイン画面の通信。プロトコルがh3のものがQUICです。
QUICの利点として以下のような点が挙げられます。
- 接続の高速化・・・TCPは3ウェイハンドシェイクの後にTLSハンドシェイクが必要ですが、QUICは接続確立と暗号化ネゴシエーションが同時に行えるので速い
- 独立したストリーム処理・・・TCPは1つのパケットロスがあると、その後ろの無関係なデータも待たされる。QUICは他ストリームを巻き込まずに済む
- コネクションの維持・・・IPアドレスではなくコネクションIDで通信相手を識別するため、wifiとモバイル回線の切り替え時も通信が途切れない
まとめ
- TCP/IPはインターネットを支えるプロトコル群の総称。IPが「届け先までの配送」、TCP/UDPが「通信の品質」を担当する
- TCPは3ウェイハンドシェイク・再送・順序保証で「確実に届く通信」を作る。HTTP、DB接続、SSHなど、僕たちは毎日使っている
- UDPは保証を捨てて低遅延に全振り。音声・映像・ゲームなど「鮮度が命」のデータに向く
- 使い分けの軸は「1件の欠落が致命的か」×「遅延が致命的か」
- Slackのメッセージング → 欠落NG → TCP(WebSocket)
- Switch 2のゲームチャット → 遅延NG → UDP(WebRTC)
- QUICのようにUDP上に信頼性を再構築する動きもある