概念 #TCP/IP #UDP #ネットワーク #DNS #QUIC #リアルタイム通信 📚 TCPIPネットワーク

UDP詳解とユースケース

UDPの設計思想・ヘッダ構造・信頼性をアプリで実装するケース・DNS・QUIC・リアルタイム通信の使い分けを解説。

UDPの設計思想

TCPが「信頼性のためにあらゆる機能を持つ」のに対し、UDPは**「できる限り薄く、速く」**を追求した設計。

UDPが提供すること:
  ✓ プロセス多重化(ポート番号による仕分け)
  ✓ チェックサムによるデータ整合性チェック(オプション)
  ✓ ブロードキャスト・マルチキャスト対応

UDPが提供しないこと:
  ✗ 到達保証(パケットが消えても通知なし)
  ✗ 順序保証(到着順は保証されない)
  ✗ 重複排除
  ✗ フロー制御・輻輳制御
  ✗ コネクション(状態管理なし)

なぜあえて信頼性を捨てるのか: TCPの信頼性機構(再送・ACK待ち)はオーバーヘッドと遅延を生む。「多少のパケットロスより低遅延が重要」「アプリ側で信頼性を制御したい」ユースケースではUDPが最適。


UDPヘッダ:シンプルな8バイト

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
├────────────────────────────────┬─────────────────────────────────┤
│         Source Port            │        Destination Port          │
├────────────────────────────────┼─────────────────────────────────┤
│            Length              │           Checksum               │
└────────────────────────────────┴─────────────────────────────────┘
              ↑ ヘッダ全体が8バイト(TCPの20バイトに対して)
フィールドビット説明
Source Port16送信元ポート(不要なら0で省略可能)
Destination Port16宛先ポート
Length16UDPヘッダ+データの合計長(最小8バイト)
Checksum16ヘッダ+データ+擬似ヘッダのチェックサム(IPv4ではオプション、IPv6では必須)

ヘッダが8バイトというのは、TCPの最小20バイトの40%のサイズ。大量の小さいメッセージを送る際のオーバーヘッド差は無視できない。


DNS:UDPの代表的ユースケース

なぜDNSはUDPを使うか

DNSクエリの特性:
  ・通常1回の往復で完結(クエリ1回 → 応答1回)
  ・レスポンスが小さい(512バイト以内が多い)
  ・多少の失敗は上位でリトライすれば良い
  ・低レイテンシが重要(名前解決はあらゆる通信の前段階)

TCP を使うと:3ウェイハンドシェイク だけで往復1.5回 → 遅すぎる
UDP を使うと:クエリ送信 → 応答受信で完結

DNS クエリの流れ

アプリケーション
  │ "api.example.com を解決したい"
  │ gethostbyname() / getaddrinfo() syscall

OS の resolverライブラリ(/etc/resolv.conf 参照)
  │ キャッシュ確認 → なければ...
  ↓ UDP port 53
フルサービスリゾルバ(再帰リゾルバ)
  │ 自身のキャッシュ確認 → なければ...

  ├──→ ルートDNSサーバー(13台)
  │      「.com を管理しているのは...」

  ├──→ .com TLDサーバー
  │      「example.com を管理しているのは...」

  └──→ example.com の権威DNSサーバー
         「api.example.com = 203.0.113.5」

  ↓ 結果をキャッシュ(TTL期間)
アプリケーションへ IPアドレスを返す

512バイト超のレスポンス → TCP fallback

DNSはレスポンスが大きい場合(DNSSEC, 多数のAレコードなど)TCPにフォールバックする。

# DNSクエリを実際に確認
dig api.example.com +short

# UDPで問い合わせ
dig @8.8.8.8 api.example.com

# TCPを強制使用(大きいレスポンス確認)
dig @8.8.8.8 api.example.com +tcp

# DNSのパケットをキャプチャ
tcpdump -i eth0 'udp port 53' -n

DHCP:ネットワーク設定の自動取得

IPアドレスを自動割り当てするプロトコル。UDPブロードキャストを使う。

PC(IPなし)                         DHCPサーバー
    │                                     │
    │── DHCP Discover ──────────────────→ │  ブロードキャスト
    │   src: 0.0.0.0:68                   │  「誰かDHCPサーバーいる?」
    │   dst: 255.255.255.255:67           │
    │                                     │
    │ ←── DHCP Offer ───────────────────  │
    │    「192.168.1.100 はどう?」        │
    │                                     │
    │── DHCP Request ───────────────────→ │  ブロードキャスト
    │   「192.168.1.100 をください」       │  (他のDHCPサーバーに断りを入れる)
    │                                     │
    │ ←── DHCP ACK ─────────────────────  │
    │    IPアドレス・GW・DNS・リース時間    │
    │    を受け取って設定完了               │

なぜブロードキャストを使うか:PC起動時はまだIPアドレスを持っていないため、ユニキャスト送信が不可能。


リアルタイム通信とUDP

RTP(Real-time Transport Protocol)

音声・動画のストリーミングに使われる。UDPの上に独自の信頼性を構築。

RTCPとRTPの組み合わせ:
  RTP  (UDP port N)   → メディアデータを送る
  RTCP (UDP port N+1) → 品質統計・同期情報を送る

RTCPパケット例:
  SR(Sender Report):送信側の統計(パケット数、バイト数、タイムスタンプ)
  RR(Receiver Report):受信側の品質(パケットロス率、ジッター、遅延)

パケットロスへの対処(アプリ側実装)

動画・音声ストリーミングの場合:
  ・多少のロスは許容(コーデックが補間)
  ・FEC(前方誤り訂正)で余分なデータを送ってロスをカバー
  ・JitterBuffer でパケット到達のばらつきを吸収してから再生

ゲームの場合:
  ・クライアント側予測(Client-side Prediction)で遅延を隠す
  ・Dead Reckoning で受信できなかったフレームの位置を補間
  ・重要なイベント(ダメージ判定)は確認応答付きで送ることも

QUIC:UDPの上に構築された次世代プロトコル

HTTP/3の基盤

QUICはUDPの上にTCPの機能(信頼性・順序保証)+ TLSを一体化して構築したプロトコル。Googleが開発し、HTTP/3の標準になった。

HTTP/1.1  →  TCP + TLS1.2  =  接続確立に 2〜3RTT
HTTP/2    →  TCP + TLS1.3  =  接続確立に 1〜2RTT(同じHoLブロッキング問題あり)
HTTP/3    →  QUIC (UDP)    =  接続確立に 0〜1RTT(0-RTTハンドシェイク)

QUICが解決したHoLブロッキング問題

HTTP/2 の問題(TCP上で多重化):
  ストリーム1: ────────────────────→
  ストリーム2: ──── ✗ (ロスト) ────→  ← ロストしたパケット待ちで
  ストリーム3: ────────────────────→    全ストリームがブロック(Head-of-Line Blocking)

QUICの解決(QUIC上で多重化):
  ストリーム1: ────────────────────→  再送中でも
  ストリーム2: ──── 再送 ──────────→  他のストリームは独立して進む
  ストリーム3: ────────────────────→

QUICのその他の特徴

0-RTT ハンドシェイク:
  2回目以降の接続では、以前のセッションチケットを使って
  ハンドシェイクなしでデータを送り始められる

コネクションマイグレーション:
  Wi-Fi → 4G に切り替わってIPアドレスが変わっても
  コネクションIDで接続を維持できる(TCPは4タプルで識別するため切断)

ユーザー空間実装:
  TCPと違ってOSカーネルに依存しないため、プロトコルの改善が速い

TCPとUDPの選択基準

┌────────────────────────────────┬──────┬──────┐
│  要件                           │ TCP  │ UDP  │
├────────────────────────────────┼──────┼──────┤
│ データが確実に届く必要がある     │  ✓   │      │
│ 順序通りに届く必要がある         │  ✓   │      │
│ コネクション管理が不要           │      │  ✓   │
│ ブロードキャスト/マルチキャスト  │      │  ✓   │
│ 低遅延が最優先                  │      │  ✓   │
│ アプリ側で信頼性を制御したい     │      │  ✓   │
│ 小さいデータの頻繁な送受信       │      │  ✓   │
│ 大量のデータ転送                 │  ✓   │      │
└────────────────────────────────┴──────┴──────┘

UDPを選ぶ主な場面:
  - DNS, DHCP, NTP(1往復で完結するプロトコル)
  - ゲーム, リアルタイム音声/映像(遅延 > 信頼性)
  - HTTP/3 / QUIC(アプリ層で信頼性を実装)
  - ログ・メトリクス収集(多少のロスは許容)
  - IoT センサーデータ(軽量プロトコルが必要)

実践:UDP通信の確認

# UDPポートの確認
ss -uln

# UDPパケットのキャプチャ
tcpdump -i eth0 udp -n

# DNS問い合わせのデバッグ
tcpdump -i eth0 'udp port 53' -nn -X

# NTPの疎通確認(UDP 123番)
ntpdate -q ntp.nict.jp

# UDP経由でデータ送受信テスト(nc)
nc -u -l 9999          # 受信側
nc -u 192.168.1.1 9999 # 送信側

出典: 図解入門 TCP/IP・TCP/IPコンピューティング・ネットワーク入門