初出 JAVA PRESS Vol.29

Java API ダイジェスト

java.nio.channels.ServerSocketChannel
java.nio.channels.SocketChannel

ServerSocketChannelクラスはとServerSocketクラス、SocketChannelクラスSocketクラスに対応するチャネルです。

この2つのチャネルはSelectableChannelの派生クラスなので非同期入出力が使用できます。この場合、Selectorクラスと共に使用されます。


ソケットに対応したチャネル

チャネルになってもソケットの基本的な流れは変化しません。まず、openメソッドを使用してチャネルをオープンします。

ソケットチャネルのオープン

次にサーバはバインドを行います。しかし、チャネルでは直接バインドが行えないので、ServerSocketオブジェクトに処理を委譲します。

ServerSocketオブジェクトの取得

サーバは次にacceptメソッドを使用して、接続要求を待ちます。クライアントはサーバに接続するためにconnectメソッドを使用します。

接続受け付け

接続

非同期入出力を使用するにはconfigureBlockingメソッドで指定します。このとき、非同期にする処理をregisterメソッドでSelectorオブジェクトに登録します。

非同期入出力

非同期入出力が可能なソケットチャネル

ソケットチャネルのオープン

public static ServerSocketChannel open() throws IOException

public static ServerSocket open() throws IOException
public static ServerSocket open(SocketAddress remote) throws IOException

オブジェクトを生成して、ソケットチャネルをオープンします。SocketChannelクラスはアドレスを指定してオープンすることができます。

ServerSocketオブジェクトの取得

public ServerSocket socket()

ServerSocketChannelオブジェクトに対応するServerSocketオブジェクトを取得します。ServerSocketChannelオブジェクトはアドレスへのバインドができないため、ServerSocketオブジェクトを取得して、bindメソッドをコールします。

接続受け付け

public SocketChannel accept() throws IOException

クライアントからの接続要求を受け付けます。このメソッドは通常の同期入出力では接続要求があるまでブロックされますが、非同期の場合ブロックされません。

戻り値はSocketChannelオブジェクトになりますが、非同期で接続待ちがなければnullになります。

接続

public boolean connect(SocketAddress remote) throws IOException

引数で指定されたアドレスに接続を行います。同期入出力時は接続されるまでブロックされますが、非同期ではブロックされません。

戻り値は接続が成功したときにtrue、非同期に接続処理が実行されている場合にfalseとなります。

リスト1、2に簡単なサンプルを示します。クライアントから送られてきた文字列をそのままクライアントにエコーバックするサンプルです。リスト1がサーバ、リスト2がクライアントです。リスト2はhostname変数が接続するホスト名になります。(例外処理は省略してあります)

非同期入出力

public SelectableChannel configureBlocking(boolean block) throws IOException

public SelectionKey register(Selector sel, int ops) throws ClosedChannelException

非同期でソケットチャネルを使用するにはconfigureBlockingメソッドで設定します。このメソッドはSelectableChannelクラスで定義されているので、ServerSocketChannelクラス、SocketChannelクラスの両方で使用できます。

非同期にするには引数をfalseにします。デフォルトは同期入出力です。

非同期ではアクセプトなどがブロックされないので、Selectorクラスを使用して待ち処理を行います。Selectorオブジェクトにはregisterメソッドを使用して登録します。登録できる処理はSelectionKeyクラスで定義されています。

引数opsでこれらの定数を指定します。引数selが登録を行うSelectorオブジェクトです。

 

リスト 1 ServerSocketChannelクラスの使用例

    InetSocketAddress address = new InetSocketAddress(InetAddress.getLocalHost(), 9000);

    ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); // オープン

    ServerSocket serverSocket = serverSocketChannel.socket();
    serverSocket.bind(address); // バインド

    SocketChannel socketChannel = serverSocketChannel.accept(); // 接続待ち
 
    ByteBuffer buffer = ByteBuffer.allocate(1024);
    socketChannel.read(buffer); // 読み込み           

    buffer.flip(); // 書き込みを行うためフリップする
            
    Charset charset = Charset.forName("UTF-16");
    System.out.println("Recieve: " + charset.decode(buffer.duplicate()));
    socketChannel.write(buffer);    // 書き込み
            
    socketChannel.close();
    serverSocketChannel.close();

 

リスト 2 SocketChannelクラスの使用例

    InetSocketAddress address = new InetSocketAddress(InetAddress.getByName(args[0]), 9000);
    SocketChannel channel = SocketChannel.open(); // オープン
    channel.connect(address); // サーバに接続
            
    Charset charset = Charset.forName("UTF-16");
    ByteBuffer message = charset.encode("Hello, SocketChannel!");
    channel.write(message); // 書き込み
            
    ByteBuffer reply = ByteBuffer.allocate(1024);
    channel.read(reply); // 読み込み
    reply.flip();
    System.out.println("Reply: " + charset.decode(reply));
            
    channel.close();