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();Iterator<SelectionKey> keys = 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等於緩衝區大小,則說明此條訊息沒讀完//需要設計複雜點的訊息結構}elseif (count == -1) {//當用戶端中斷連線時會觸發read事件,並且可以讀到-1,這時關閉通道sc.close();key.cancel();continue;}} catch (Exception e) {// TODO: handle exceptionsc.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 blocke.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 blocke.printStackTrace();}}public static void main(String[] args) {new NIOS().start(802);}}
JAVA NIO 筆記(1)