JavaでUDP通信をする方法を調べました。DatagramSocket
を使ったやり方は知っていましたが、今回はjava.nioを使ったやり方を調べました。
受信する
まずはUDPメッセージが送られてくることがわかっている前提で、受信するコードを書いてみます。
// UDPチャンネルを作成
DatagramChannel channel = DatagramChannel.open();
// 9999番ポート宛のUDPメッセージを受け取るようにする
channel.socket().bind(new InetSocketAddress(9999));
// メッセージを受け取るためのバッファを用意する。
// バッファよりメッセージが大きい場合、入り切らなかったメッセージは破棄される。
ByteBuffer buf = ByteBuffer.allocate(453);
buf.clear();
// メッセージの受信を待機する
channel.receive(buf);
// データをbyte[]に受け取る
buf.flip();
byte[] data = new byte[buf.limit()];
buf.get(data);
送信する
次に送信する側のコードを書いてみます。
// UDPチャンネルを作成
DatagramChannel channel = DatagramChannel.open();
// 9999番ポートからUDPメッセージを送るようにする
channel.socket().bind(new InetSocketAddress(9999));
// 送信するデータをByteBufferの形にする。
// ここではString->byte[]->ByteBufferと変換している。
String newData = "New String to write to file..." + System.currentTimeMillis();
ByteBuffer buf = ByteBuffer.allocate(48);
buf.clear();
buf.put(newData.getBytes());
buf.flip();
// 送信
int bytesSent = channel.send(buf, new InetSocketAddress("127.0.0.1", 41234));
受信する時も送信する時も、DatagramChannel
を作成してソケットをバインドするところまでは同じです。そして送受信したい内容をByteBuffer
に変換してやりとりします。
自分で低レベルなプロトコルを実装したい!という場合でないなら、メッセージの内容をJSON等の方式で文字列化して、String
->byte[]
->ByteBuffer
として送るのが汎用的に使えて良いのではないかと思います。
Javaアプリケーション同士の通信であればObjectInputStreamとObjectOutputStreamを使って任意のオブジェクトを直接やりとりすることも可能です。
注意点としては、UDPではTCPのように相手にメッセージがきちんと届くことは保証されてはいないので、**届かなくてもエラーになりません。**なのでデバッグ中にコードにミスがあっても見つかりにくいことがあります。
番外編
ちなみにNode.jsだとUDPの送受信はこんなに簡単です。
const dgram = require('dgram');
const server = dgram.createSocket('udp4');
server.on('message', (msg, rinfo) => {
console.log(`server got: ${msg} from ${rinfo.address}:${rinfo.port}`);
});
// 9999番ポートで受信を待機
server.bind(9999);
const dgram = require('dgram');
const server = dgram.createSocket('udp4');
server.send('Hello', 9999, '127.0.0.1', (err, bytes) => {
console.log(err, bytes)
});
JavaアプリケーションのUDPメッセージ送受信部分をデバッグする時には仮のメッセージ送信用にNode.jsでテストプログラムを書くと便利かもしれませんね。