- 4.1. データグラム通信
- 4.2. DatagramSocketクラス
- 4.3. DatagramPacketクラス
- 4.4. データグラム通信プログラム
- 4.5. プログラムの実行
4.4. データグラム通信プログラム
それではUDP通信を利用した通信プログラムを作成してみましょう。前節までに作成した文字列送受信プログラムをより簡単なものにして、ここでは一方向にメッセージを送信するだけのプログラムを作成します。
まず送信側のプログラムを示します。
リスト DatagramSender.java
import java.net.DatagramSocket; import java.net.DatagramPacket; import java.net.InetSocketAddress; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.IOException; public class DatagramSender { public static final int SERVER_PORT = 10007; public static final int PACKET_SIZE = 1024; public static void main(String args[]) { DatagramSocket socket = null; InetSocketAddress remoteAddress = new InetSocketAddress(args[0], SERVER_PORT); try { BufferedReader keyIn = new BufferedReader(new InputStreamReader(System.in)); socket = new DatagramSocket(); String message; while ( (message = keyIn.readLine()).length() > 0 ) { byte[] buf = message.getBytes(); DatagramPacket packet = new DatagramPacket(buf, buf.length, remoteAddress); socket.send(packet); } } catch (IOException e) { e.printStackTrace(); } finally { if (socket != null) { socket.close(); } } } }
15〜16行目では、パケットのあて先に利用するソケットアドレスを設定しています。送信先ホストはプログラムの引数で設定したアドレスとし、ポート番号は10007番とします。
InetSocketAddress remoteAddress = new InetSocketAddress(args[0], SERVER_PORT);
21行目では、パケットの送信に利用するDatagramSocketを作成しています。ポート番号は自動的に割り振られるものを利用しています。
socket = new DatagramSocket();
24〜26行目では、送信するパケットを作成しています。まず、キーボードから入力された文字列をbyte型の配列に変換し、そのデータを用いてパケットを作成しています。
byte[] buf = message.getBytes(); DatagramPacket packet = new DatagramPacket(buf, buf.length, remoteAddress);
27行目で、作成したパケットを送信します。
socket.send(packet);
次に受信側のプログラムを見てみましょう。
リスト DatagramReceiver.java
import java.net.DatagramSocket; import java.net.DatagramPacket; import java.io.IOException; public class DatagramReceiver { public static final int SERVER_PORT = 10007; public static final int PACKET_SIZE = 1024; public static void main(String args[]) { DatagramSocket socket = null; byte[] buf = new byte[PACKET_SIZE]; DatagramPacket packet = new DatagramPacket(buf, buf.length); try { socket = new DatagramSocket(SERVER_PORT); System.out.println("DatagramReceiverが起動しました(port=" + socket.getLocalPort() + ")"); while (true) { socket.receive(packet); String message = new String(buf, 0, packet.getLength()); System.out.println(packet.getSocketAddress() + " 受信: " + message); } } catch (IOException e) { e.printStackTrace(); } finally { if (socket != null) { socket.close(); } } } }
13〜14行目で、受信パケットの入れ物を作成しています。まずbyte型の配列を準備し、その配列を引数にしてDatagramPacketのコンストラクタを呼び出しています。
byte[] buf = new byte[PACKET_SIZE]; DatagramPacket packet = new DatagramPacket(buf, buf.length);
17行目では、パケットの送受信に用いるソケットを作成しています。送信側と同じ10007番ポートを利用しています。
socket = new DatagramSocket(SERVER_PORT);
21行目で、パケットの到着を待っています。DatagramSocketクラスのreceiveメソッドは、ServerSocketクラスのacceptメソッドと同じように、パケットが到着するかタイムアウトなどにより中断されるまで動作をブロックします。到着したパケットはreceiveメソッドの引数で指定したpacketに格納されます。
socket.receive(packet);
22行目で、受信したパケットから文字列を取り出しています。byte配列から文字列を作成するStringクラスのコンストラクタを利用しています。
String message = new String(buf, 0, packet.getLength());
23〜24行目で、受信した文字列を、送信元のアドレスとともに表示しています。送信元のアドレスは、DatagramPacketクラスのgetSocketAddressメソッドで取得することができます。
System.out.println(packet.getSocketAddress() + " 受信: " + message);
このプログラムは前節のMultiEchoServerのようにマルチスレッドにはしていませんが、複数のクライアントからの接続を同時に処理することができます。DatagramSocketは固定的な接続を必要としないため、ソケット自体にはなにも変更を加えることなく、1つのソケットで複数の相手と通信することができます。