您的位置:首页 > 运维架构

nio SelectionKey.OP_WRITE 的问题

2017-03-29 12:50 295 查看


SelectionKey理解(总结)

SelectKey注册了写事件,不在合适的时间去除掉,会一直触发写事件,因为写事件是代码触发的
client.register(selector, SelectionKey.OP_WRITE);
或者sk.interestOps(SelectionKey.OP_WRITE)
 执行了这以上任一代码都会无限触发写事件,跟读事件不同,一定注意
 
 
nio的select()的时候,只要数据通道允许写,每次select()返回的OP_WRITE都是true。所以在nio的写数据里面,我们在每次需要写数据之前把数据放到缓冲区,并且注册OP_WRITE,对selector进行wakeup(),这样这一轮select()发现有OP_WRITE之后,将缓冲区数据写入channel,清空缓冲区,并且反注册OP_WRITE,写数据完成。
这里面需要注意的是,每个SocketChannel只对应一个SelectionKey,也就是说,在上述的注册和反注册OP_WRITE的时候,不是通过channel.register()和key.cancel()做到的,而是通过key.interestOps()做到的。代码如下:
public void write(MessageSession session, ByteBuffer buffer) throws ClosedChannelException {

   SelectionKey key = session.key();

   if((key.interestOps() & SelectionKey.OP_WRITE) == 0) {

    key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);

   }

   try {

   writebuf.put(buffer);

   } catch(Exception e) {

    System.out.println("want put:"+buffer.remaining()+", left:"+writebuf.remaining());

    e.printStackTrace();

   }

   selector.wakeup();

}
.....
while(true) {

   selector.select();

   .....

        if(key.isWritable()) {

         MessageSession session = (MessageSession)key.attachment();

         //System.out.println("Select a write");

         synchronized(session) {

          writebuf.flip();

          SocketChannel channel = (SocketChannel)key.channel();

          int count = channel.write(writebuf);

          //System.out.println("write "+count+" bytes");

          writebuf.clear();

          key.interestOps(SelectionKey.OP_READ);

         }

        }

        ......

    }
要点一:不推荐直接写channel,而是通过缓存和attachment传入要写的数据,改变interestOps()来写数据;
要点二:每个channel只对应一个SelectionKey,所以,只能改变interestOps(),不能register()和cancel()。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: