非同期入出力が可能なソケットチャネル
ソケットチャネルのオープン
- ServerSocketChannel#open
public static ServerSocketChannel open() throws IOException
- SocketChannel#open
public static ServerSocket open() throws IOException
public static ServerSocket open(SocketAddress remote) throws IOException
オブジェクトを生成して、ソケットチャネルをオープンします。SocketChannelクラスはアドレスを指定してオープンすることができます。
ServerSocketオブジェクトの取得
- ServerSocketChannel#socket
public ServerSocket socket()
ServerSocketChannelオブジェクトに対応するServerSocketオブジェクトを取得します。ServerSocketChannelオブジェクトはアドレスへのバインドができないため、ServerSocketオブジェクトを取得して、bindメソッドをコールします。
接続受け付け
- ServerSocketChannel#accept
public SocketChannel accept() throws IOException
クライアントからの接続要求を受け付けます。このメソッドは通常の同期入出力では接続要求があるまでブロックされますが、非同期の場合ブロックされません。
戻り値はSocketChannelオブジェクトになりますが、非同期で接続待ちがなければnullになります。
接続
- SocketChannel#connect
public boolean connect(SocketAddress remote) throws IOException
引数で指定されたアドレスに接続を行います。同期入出力時は接続されるまでブロックされますが、非同期ではブロックされません。
戻り値は接続が成功したときにtrue、非同期に接続処理が実行されている場合にfalseとなります。
リスト1、2に簡単なサンプルを示します。クライアントから送られてきた文字列をそのままクライアントにエコーバックするサンプルです。リスト1がサーバ、リスト2がクライアントです。リスト2はhostname変数が接続するホスト名になります。(例外処理は省略してあります)
非同期入出力
- SelectableChannel#configureBlocking
public SelectableChannel configureBlocking(boolean block) throws IOException
- SelectableChannel#register
public SelectionKey register(Selector sel, int ops) throws ClosedChannelException
非同期でソケットチャネルを使用するにはconfigureBlockingメソッドで設定します。このメソッドはSelectableChannelクラスで定義されているので、ServerSocketChannelクラス、SocketChannelクラスの両方で使用できます。
非同期にするには引数をfalseにします。デフォルトは同期入出力です。
非同期ではアクセプトなどがブロックされないので、Selectorクラスを使用して待ち処理を行います。Selectorオブジェクトにはregisterメソッドを使用して登録します。登録できる処理はSelectionKeyクラスで定義されています。
- アクセプト SelectionKey.OP_ACCEPT
- コネクト SelectionKey.OP_CONNECT
- 読み込み SelectionKey.OP_READ
- 書き込み SelectionKey.OP_WRITE
引数opsでこれらの定数を指定します。引数selが登録を行うSelectorオブジェクトです。
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();
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();