N-04: UDP 通信(DatagramSocket)
DatagramSocket と DatagramPacket を使った UDP 通信の基本を解説します。UDP(User Datagram Protocol)は TCP と異なり接続確立を行わないコネクションレスなプロトコルです。 オーバーヘッドが小さく、遅延に敏感なリアルタイムアプリケーションに適しています。
TCP と UDP の違い
| 項目 | TCP | UDP |
|---|---|---|
| 接続方式 | コネクション型(3ウェイハンドシェイク) | コネクションレス |
| 信頼性 | 高い(順序保証・再送あり) | なし(ベストエフォート) |
| 速度・遅延 | 比較的遅い(確認応答あり) | 高速・低遅延 |
| パケット順序 | 保証される | 保証されない |
| ユースケース | HTTP、FTP、メール | DNS、動画ストリーミング、ゲーム |
| Java クラス | ServerSocket / Socket | DatagramSocket / DatagramPacket |
サンプルコード
受信側(レシーバー)を別スレッドで起動し、送信側がデータグラムパケットを送る実装例です。 ログ収集や監視データの送信など、多少のパケット欠落が許容されるユースケースに適したパターンです。
よくあるミス・注意点
⚠️ UDP はコネクションレスなので相手が受信できなくてもエラーにならない
senderSocket.send(packet) は 受信側が存在しない場合でも例外をスローせずに正常終了します。 「送信が成功した」=「相手が受信した」ではない点に注意してください。 受信確認が必要な場合は TCP を使うか、アプリケーション層で確認応答の仕組みを自前で実装する必要があります。
// UDP: 受信側がいなくても例外が発生しない senderSocket.send(packet); // 相手が起動していなくても成功する // 受信確認が必要な場合は TCP(ServerSocket / Socket)を使うこと
📌 1 つの DatagramPacket の最大サイズは 65507 バイト
UDP ペイロードの理論的な最大サイズは 65507 バイト(65535 - IP ヘッダー 20 バイト - UDP ヘッダー 8 バイト)です。 これを超えるデータは送信できません。また、ネットワーク経路の MTU(最大転送単位)によって 実際にはもっと小さいサイズに制限される場合があります。 大きなデータを送る場合は TCP を使うか、データを分割して送ることを検討してください。
📌 パケットの順序は保証されない
UDP ではパケットが送信した順番通りに届く保証はありません。 連続して複数のパケットを送ると、受信側では逆順や途中抜けで届く場合があります。 順序が重要なデータ(例: 動画フレーム番号、トランザクション ID)は アプリケーション側でシーケンス番号を付与して管理する必要があります。
📌 UDP は低遅延が求められるアプリに向く
TCP の3ウェイハンドシェイクや確認応答(ACK)がない分、UDP は遅延が小さく高速です。 オンラインゲーム(位置情報の送信)、動画・音声ストリーミング、DNS クエリなど 「多少のパケット欠落より低遅延を優先したい」場面で活躍します。 信頼性よりもリアルタイム性が重要な場合に UDP を選択しましょう。
テストする観点
- 受信側を起動した後に送信すると、メッセージが正しく届くか
- 日本語を含む文字列が UTF-8 で正しくエンコード・デコードされるか(バイト列のエンコーディング確認)
- 送信したバイト数と受信した
packet.getLength()が一致するか - 1024 バイトを超えるペイロードを送信した場合に正しく処理されるか(バッファサイズの境界値テスト)
packet.getAddress()とpacket.getPort()に送信元情報が正しく格納されているか- 受信タイムアウト(
socket.setSoTimeout())を設定した場合にパケットが来なければSocketTimeoutExceptionが発生するか