【Java】UDP通信を利用したデータの送受信

2018年12月26日

本稿は、より速度が求められる環境において使われる、UDP通信をやっていきます。



UDP通信

UDP通信はコネクションを確立せずに通信します。
データを送信する側は目的のアドレスにデータを一方的に送りつけて終了するというシンプルな処理になります。

その分通信のオーバーヘッドがなくなり速度が速くなります。

ただし、データの整合性や、到達順序が保障されないなどといったデメリットもあります。

プログラムを組むうえでは、テストプログラムの段階ではUDPのほうが簡単かもしれませんが、本格的なアプリケーションで通信処理を実装する場合はUDPのほうが、考慮すべきことが多く難易度が高い気がします。

例えば、一度に送信できるパケットの量なども考慮しておかなければなりません。

DatagramSocketクラス

通信処理を行うクラスです。

データを送信する場合、何も指定せずインスタンス化、受信する場合はポート番号のみ指定します。

DatagramSocket sock = new DatagramSocket();//送信
DatagramSocket sock = new DatagramSocket(ポート番号);//受信

DatagramPacketクラス

データパケットをあらわすクラスです。

このクラスにバイト配列などを格納し、データを送信します。

受信時もこのクラスから取り出し処理を行います。

送信
DatagramPacket packet = new DatagramPacket(バイト配列, データの大きさ,new InetSocketAddress(送信先ipやホストなど,送信先ポート番号));//送信
sock.send(packet);//パケットの送信
受信
DatagramPacket packet = new DatagramPacket(バイト配列, データの大きさ);//受信
sock.receive(packet);//パケットの受信

データの送受信サンプル

UDPでのデータの送受信を行う、シンプルなサンプルを作ってみます。

クライアントが文字列を送信し、サーバが受信するだけです。

Client.java
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;

public class Client {

	public static void main(String[] args) throws IOException {
		String sendData = "UDPてすとですよ";//送信データ
		byte[] data = sendData.getBytes("UTF-8");//UTF-8バイト配列の作成
		DatagramSocket sock = new DatagramSocket();//UDP送信用ソケットの構築
		DatagramPacket packet = new DatagramPacket(data, data.length,new InetSocketAddress("localhost",10005));//指定アドレス、ポートへ送信するパケットを構築
		sock.send(packet);//パケットの送信
		System.out.println("UDP送信:"+sendData);//送信データにの表示
		sock.close();//ソケットのクローズ
	}
}
Server.java
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.util.Arrays;

public class Server {

	public static void main(String[] args) throws IOException {
		DatagramSocket sock = new DatagramSocket(10005);//10005ポートでUDP受信用ソケット構築
		byte[] data = new byte[1024];//受信最大バッファ
		DatagramPacket packet = new DatagramPacket(data, data.length);//受信用パケットを構築
		sock.receive(packet);//受信
		System.out.println("UDP受信:"+new String(Arrays.copyOf(packet.getData(),packet.getLength()),"UTF-8"));//受信データの表示
		sock.close();//ソケットのクローズ
	}
}
クライアント側実行結果

UDP送信:UDPてすとですよ

サーバー実行結果

UDP受信:UDPてすとですよ

DatagramChannelクラス

DatagramChannelを使用すると以前紹介したセレクタを利用してUDP通信することができます。

セレクタは下記の記事で紹介しました。

DatagramChannelもServerSocketChannelと同じくAbstractSelectableChannelを継承しているため、同じように使えます。

これを利用すると複数端末間の通信処理も簡単に実装できそうです。

バイト配列の取り扱いに便利なByteBufferを利用できるのも利点です。

DatagramChannelはopenメソッドでインスタンスを取得し、sendメソッドで送信処理を行います。

送信する場合
DatagramChannel channel = DatagramChannel.open();
channel.send(バイトバッファ, new InetSocketAddress(送信先ipやホスト, ポート番号));
受信する場合はbindメソッドで受信準備をします。
DatagramChannel channel = DatagramChannel.open();
channel.bind(new InetSocketAddress(ポート番号));
channel.receive(バイトバッファ);//データの受信

DatagramChannelによる送受信サンプル

それではDatagramChannelを使った送受信のサンプルも作ってみましょう。

Client.java
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.charset.StandardCharsets;

public class Client {

	public static void main(String[] args) throws IOException {
		String sendData = "UDPチャネルのてすとですよ";//送信データ
		DatagramChannel channel = DatagramChannel.open();//DatagramChannelの作成
		ByteBuffer bb = StandardCharsets.UTF_8.encode(sendData);//送信データをUTF8バイト配列に変換
		channel.send(bb, new InetSocketAddress("localhost", 10003));//10003へ送信
		System.out.println("UDPチャネル送信:"+sendData);//送信データの表示
		channel.close();//チャネルクローズ
	}
}
Server.java
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.charset.StandardCharsets;

public class Server {

	public static void main(String[] args) throws IOException {
		DatagramChannel channel = DatagramChannel.open();//データグラムチャネルの作成
		channel.bind(new InetSocketAddress(10003));//受信ポートの指定(10003で受け付け)
		ByteBuffer bb = ByteBuffer.allocate(1024);//最大1024バイト受信バッファの作成
		channel.receive(bb);//データの受信
		bb.flip();//現在のデータを受信データとして確定させる
		System.out.println("UDPチャネル受信:"+StandardCharsets.UTF_8.decode(bb).toString());//UTF8でバイト配列からStringへ変換
		channel.close();//チャネルのクローズ
	}
}
クライアント側実行結果

UDPチャネル送信:UDPチャネルのてすとですよ

サーバー実行結果

UDPチャネル受信:UDPチャネルのてすとですよ

これでUDP通信の基本処理もできると思います。

時間ができたら通信系のゲームも一本作りたいところですね。

Java

Posted by nompor