Java NIO 笔记
0. 存在多种通道,key.channel()返回的是该事件的宿主,如果key是OP_ACCEPT事件,则返回的会是ServerSocketChannel.
1. SelectionKey.cancel : cancel()方法是永久的注销SelectionKey.OPxxxx,并将其放入selector的canceled set中。在下一次调用select()方法的时候,这些键会从该选择器的所有键集中移除,它关联的信道也不在监听了(除非它又重新注册)。
2.NIO HTTP Server Example :
import java.io.*; import java.nio.*; import java.nio.channels.*; import java.util.Iterator; import java.net.*; public class NonblockingSingleFileHTTPServer { private ByteBuffer contentBuffer; private int port = 80; public NonblockingSingleFileHTTPServer( ByteBuffer data, String encoding, String MIMEType, int port) throws UnsupportedEncodingException { this.port = port; String header = "HTTP/1.0 200 OK\r\n" + "Server: OneFile 2.0\r\n" + "Content-length: " + data.limit( ) + "\r\n" + "Content-type: " + MIMEType + "\r\n\r\n"; byte[] headerData = header.getBytes("ASCII"); ByteBuffer buffer = ByteBuffer.allocate( data.limit( ) + headerData.length); buffer.put(headerData); buffer.put(data); buffer.flip( ); this.contentBuffer = buffer; } public void run( ) throws IOException { ServerSocketChannel serverChannel = ServerSocketChannel.open( ); ServerSocket serverSocket = serverChannel.socket( ); Selector selector = Selector.open( ); InetSocketAddress localPort = new InetSocketAddress(port); serverSocket.bind(localPort); serverChannel.configureBlocking(false); //服务端通道只注册accept事件 serverChannel.register(selector, SelectionKey.OP_ACCEPT); while (true) { selector.select( ); Iterator keys = selector.selectedKeys( ).iterator( ); while (keys.hasNext( )) { SelectionKey key = (SelectionKey) keys.next( ); //一定要删除已处理过的事件,否则下一次select仍然会提交给你 keys.remove( ); try { if (key.isAcceptable( )) { ServerSocketChannel server = (ServerSocketChannel) key.channel( ); SocketChannel channel = server.accept( ); channel.configureBlocking(false); //给客户端通道注册可读事件 SelectionKey newKey = channel.register(selector, SelectionKey.OP_READ); } else if (key.isWritable( )) { SocketChannel channel = (SocketChannel) key.channel( ); ByteBuffer buffer = (ByteBuffer) key.attachment( ); synchronized (buffer) { if (buffer.hasRemaining( )) { //可写则写 channel.write(buffer); } else { // we're done //写完关闭客户端连接 channel.close( ); } } } else if (key.isReadable( )) { // Don't bother trying to parse the HTTP header. // Just read something. SocketChannel channel = (SocketChannel) key.channel( ); ByteBuffer buffer = ByteBuffer.allocate(4096); channel.read(buffer); //buffer.flip(); //System.out.println(new String(buffer.array())); // switch channel to write-only mode //更改为只注册可写事件 key.interestOps(SelectionKey.OP_WRITE); key.attach(contentBuffer.duplicate( )); } } catch (IOException ex) { ex.printStackTrace(); //取消key所对应的事件 key.cancel( ); try { key.channel( ).close( ); } catch (IOException cex) { cex.printStackTrace(); } } } } } public static void main(String[] args) { args = new String[]{"I:\\说明_Readme.html","801","gb2312"}; if (args.length == 0) { System.out.println( "Usage: java NonblockingSingleFileHTTPServer file port encoding"); return; } try { String contentType = "text/plain"; if (args[0].endsWith(".html") || args[0].endsWith(".htm")) { contentType = "text/html"; } FileInputStream fin = new FileInputStream(args[0]); FileChannel in = fin.getChannel( ); ByteBuffer input = in.map(FileChannel.MapMode.READ_ONLY, 0, in.size( )); // set the port to listen on int port; try { port = Integer.parseInt(args[1]); if (port < 1 || port > 65535) port = 80; } catch (Exception ex) { port = 80; } String encoding = "ASCII"; if (args.length > 2) encoding = args[2]; NonblockingSingleFileHTTPServer server = new NonblockingSingleFileHTTPServer( input, encoding, contentType, port); server.run( ); } catch (Exception ex) { ex.printStackTrace( ); System.err.println(ex); } } }
躲猫猫社团团长 http://t.sina.com.cn/coolria