EeBlog(テクニカルブログ)

第113回 ソケットチャンネルの入出力

引き続き「ソケットチャンネルの入出力」です。

今回はDatagramChannelによる通信で受信側のプログラムを実装します。
DatagramChannelもSelectableChannelを継承しているので、非ブロックモードで入出力を行うことができます。

次のサンプルコードは、データを受信するプログラムです。


import java.net.InetSocketAddress;
 import java.nio.ByteBuffer;
 import java.nio.channels.DatagramChannel;
 import java.nio.channels.SelectionKey;
 import java.nio.channels.Selector;
 import java.nio.charset.Charset;
 import java.util.Iterator;


 public class Main {


     public static void main(String[] args) {
         DatagramChannel datagramChannel = null;
         try {
             datagramChannel = DatagramChannel.open();
             InetSocketAddress inetSocketAddress = new InetSocketAddress(9999);
             datagramChannel.socket().bind(inetSocketAddress);
             datagramChannel.configureBlocking(false);
             Selector selector = Selector.open();
             datagramChannel.register(selector, SelectionKey.OP_READ);
             while (selector.select() > 0) {
                 for (Iterator iterator 
                      = selector.selectedKeys().iterator();
                                       iterator.hasNext();) {
                     SelectionKey selectionKey = iterator.next();
                     iterator.remove();
                     if (selectionKey.isReadable()) {
                         doReceive(selectionKey);
                     }
                 }
             }
         } catch (Exception e) {
             e.printStackTrace();
         } finally {
             try {
                 datagramChannel.close();
             } catch (Exception e) {}
         }


     }


     private static void doReceive(SelectionKey selectionKey) {
         DatagramChannel datagramChannel 
                     = (DatagramChannel) selectionKey.channel();
         ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
         Charset charset = Charset.forName("Shift-JIS");
         try {
             datagramChannel.receive(byteBuffer);
             byteBuffer.flip();
             System.out.println(charset.decode(byteBuffer));
         } catch (Exception e) {
             e.printStackTrace();
         }
     }
 }

DatagramChannelはconfigureBlockingメソッドで非ブロックモードに設定し、セレクタに登録しています。
DatagramChannelはデータ受信が可能なときにセレクタによって選択されるので、receiveメソッドは待機することなくデータを受信することができます。