1.key.attachment为空? sc.register(selector, SelectionKey.OP_WRITE|SelectionKey.OP_READ,bb); 使用这种方法注册事件时,需要添加第三个参数:attachment对象;或者使用 key.interestOps(SelectionKey.OP_WRITE | SelectionKey.OP_READ)方法;
2.如何捕捉到客户端断开事件?断开时会触发readable key,所以在isreadable中判断read的返回值是否为-1
3.如果不注册写事件则写操作无疑和同步方式一样了,如果注册了写事件则需要在写完时取消该事件
4.key.cancel会同时取消读与写事件
package my;import java.io.IOException;import java.io.UnsupportedEncodingException;import java.net.InetSocketAddress;import java.net.ServerSocket;import java.nio.ByteBuffer;import java.nio.channels.SelectionKey;import java.nio.channels.Selector;import java.nio.channels.ServerSocketChannel;import java.nio.channels.SocketChannel;import java.util.Iterator;public class NIOS { public static final int SIZE = 1024; void start(int port) { ByteBuffer buffer = ByteBuffer.allocate(SIZE); try { ServerSocketChannel s = ServerSocketChannel.open(); ServerSocket socket = s.socket(); Selector selector = Selector.open(); InetSocketAddress addr = new InetSocketAddress(port); socket.bind(addr); s.configureBlocking(false); s.register(selector, SelectionKey.OP_ACCEPT); while (true) { int selCount = selector.select(); Iteratorkeys = selector.selectedKeys().iterator(); while (keys.hasNext()) { System.out.println("select Count:" + selCount); SelectionKey key = (SelectionKey) keys.next(); keys.remove(); if (key.isAcceptable()) { System.out.println("isacc..."); ServerSocketChannel ssc = (ServerSocketChannel) key.channel(); SocketChannel sc = ssc.accept(); sc.configureBlocking(false); sc.register(selector, SelectionKey.OP_READ); } else if (key.isReadable()) { System.out.println("readable.."); SocketChannel sc = (SocketChannel) key.channel(); try { int count = sc.read(buffer); System.out.println("Read byte:" + count); //log(buffer); if(count==SIZE){ //如果count等于缓冲区大小,则说明此条消息没读完 //需要设计复杂点的消息结构 }else if (count == -1) { //当客户端断开连接时会触发read事件,并且可以读到-1,这时关闭通道 sc.close(); key.cancel(); continue; } } catch (Exception e) { // TODO: handle exception sc.close(); key.cancel(); System.out.println("close!"); continue; } buffer.flip(); ByteBuffer bb = buffer.duplicate(); key.attach(bb); buffer.clear(); // sc.register(selector, // SelectionKey.OP_WRITE|SelectionKey.OP_READ,bb); //等价于 key.interestOps(SelectionKey.OP_WRITE | SelectionKey.OP_READ); //通常不会注册写事件,除非写的内容巨大,注册写事件后注意取消 } else if (key.isWritable()) { System.out.println("writable.."); SocketChannel sc = (SocketChannel) key.channel(); ByteBuffer att = (ByteBuffer) key.attachment(); if (att.hasRemaining()) { int count = sc.write(att); System.out.println("write:" + count + " byte,hasRemain:" + att.hasRemaining()); } else { //写完后取消可写事件,仅监听可读事件 key.interestOps(SelectionKey.OP_READ); } } } } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static void log(ByteBuffer buf){ try { System.out.println(new String(buf.array(),0,buf.limit(),"utf8")); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static void main(String[] args) { new NIOS().start(802); }}