[an error occurred while processing this directive]
[an error occurred while processing this directive]System.err.println("Accepting : " + address.getAddress());してるけど、ここで表示されるアドレス(ホスト名)に対してtelnetして下さい。
import java.io.IOException; import java.net.*; import java.nio.*; import java.nio.channels.*; import java.nio.charset.*; public class NIOServer { ServerSocketChannel ssc; public NIOServer(int port) { InetSocketAddress address; try { ssc = ServerSocketChannel.open(); address = new InetSocketAddress(InetAddress.getLocalHost(), port); System.err.println("Accepting : " + address.getAddress()); ssc.socket().bind(address); } catch (IOException e){ e.printStackTrace();} } public void finalize(){ try { ssc.close(); } catch(IOException e) { e.printStackTrace(); } } public void start() throws IOException { SocketChannel sc = ssc.accept(); try { ByteBuffer buf = ByteBuffer.allocate(1024); sc.read(buf); buf.flip(); CharsetDecoder decoder = Charset.forName("ASCII").newDecoder(); CharBuffer cb = decoder.decode(buf); System.out.println("Rcvd : " + cb.toString()); } catch (IOException e) { e.printStackTrace(); } sc.close(); } public static void main(String[] args) { int port = 12345; NIOServer s = new NIOServer(port); try{ s.start(); } catch(IOException e){ e.printStackTrace(); } } }普通のjava.ioを使った場合に比べて長いですね… でもこれでも最大限シンプルにした結果です。まずアドレスとポートを指定して、サーバーソケットに当たるServerSockerChannelを作ります。そしてこれをバインドして、acceptで待機します。リクエストが来たら、新しいソケットであるSocketChannelが返ってくるので、これを使って読み書きします。読み書きはByteBufferを通して行います。なんとかstreamよりちょっと高速だと期待されるらしい。
selector = Selector.open();で出来ます。
ServerSockerChannel ssc; // (これが登録したいソケット/チャネル) ... ssc.register(selector, SelectionKey.OP_ACCEPT);のように、チャネル側のregisterメソッドを呼びます。これでselectorへの登録が完了します。
while (selector.select() > 0) { //(色んな処理) }さてこのループの中では、データが来たりしてセレクトされたチャネルについての操作を書くことになります。このリストは先も書いたとおりselectedKeys()で取得できます。一つ大事なことは、Iteratorで処理するときに、remove()でセレクトされたキーを削除する必要があることです。そうでないと、このチャネルはセレクトされたリストに入り続けてしまいます。
Iterator itr = selector.selectedKeys().iterator(); while (itr.hasNext()) { SelectionKey key = (SelectionKey)itr.next(); itr.remove(); //これ大事 if (key.isAcceptable()) { // 新しいコネクションの処理 } else if (key.isReadable()) { // データが到着したから読む } }さて、これらをまとめたのが次のミニプログラムです。
import java.io.IOException; import java.net.*; import java.nio.*; import java.nio.channels.*; import java.nio.charset.*; import java.util.Iterator; public class SelectorServer { Selector selector; public SelectorServer(int port) { InetSocketAddress address; try { selector = Selector.open(); ServerSocketChannel ssc = ServerSocketChannel.open(); ssc.configureBlocking(false); address = new InetSocketAddress(InetAddress.getLocalHost(), port); ssc.socket().bind(address); // Register the channel (ssc) to the selector ssc.register(selector, SelectionKey.OP_ACCEPT); } catch (IOException e) { e.printStackTrace();} } //(finalize()は全部書き直し) public void finalize(){ try { Iterator itr = selector.keys().iterator(); while(itr.hasNext()){ SelectionKey key = (SelectionKey)itr.next(); Channel c = key.channel(); System.out.println("Closing " + c.toString()); c.close(); } } catch(IOException e) { e.printStackTrace(); } } //(start()も全部書き直し) public void start() { try { while (selector.select() > 0) { // Get "selected" objects Iterator itr = selector.selectedKeys().iterator(); while (itr.hasNext()) { SelectionKey key = (SelectionKey)itr.next(); itr.remove(); if (key.isAcceptable()) { ServerSocketChannel ssc = (ServerSocketChannel)key.channel(); SocketChannel sc = ssc.accept(); sc.configureBlocking(false); // register new socket to the selector sc.register(selector, SelectionKey.OP_READ); System.err.println("Connected : " + sc.socket().toString()); } else if (key.isReadable()) { SocketChannel sc = (SocketChannel) key.channel(); ByteBuffer buf = ByteBuffer.allocate(1024); if (sc.read(buf) < 0) { sc.close(); continue; } buf.flip(); CharsetDecoder decoder = Charset.forName("ASCII").newDecoder(); CharBuffer cb = decoder.decode(buf); System.out.println("Rcvd from " + sc.socket().toString()); System.out.println(" : " + cb.toString()); } } } } catch (IOException e) { e.printStackTrace(); return; } } public static void main(String[] args) { SelectorServer s = new SelectorServer(12345); s.start(); } }select()ではビット操作だったのが、Iteratorとかを使ってスマートにまとめられています。でも速さは不明… でも自分で色んなソケットを見張るコードを書くよりは楽かも。