取消选择键但之后重新使用它

Cancel a selection key but reuse it afterwards

我想首先将通道注册到选择器以仅在连接时执行 select(),然后在仅写入时执行。

像这样:

SelectionKey key = server.register(selector, SelectionKey.OP_CONNECT);
server.connect(address);
int readyChannels = 0;
while (readyChannels == 0) readyChannels = selector.select(config.connectTimeout);
server.finishConnect();
key.cancel();

key = server.register(selector, SelectionKey.OP_WRITE);
// write something to the channel and check timeout 
// with selector.select(config.writeTimeout)

但是,当我到达代码中的第二个 register(...) 时,我得到一个 CancelledKeyException

还有其他方法吗?

正确的做法是每次都定义一个新的选择器吗?

P.S。我知道我可以使用 key.isWritable() 等等。

  1. 如果 finishConnect() returns false 就好像返回了 true 一样继续进行是不正确的。

  2. 你的问题是你没有在取消和注册之间调用选择器,所以还有未完成的事情。这里最简单的解决办法就是去掉cancel和register,直接调整已有selection key的interestOps即可。

  3. 然而,由于您只是在连接完成之前有效地阻塞,所以在 in 阻塞模式下执行连接并转到非阻塞会更简单之后,对于随后的 I/O:

    // Still in blocking mode, no register() yet ...
    server.socket().connect(address, connectTimeout);
    server.configureBlocking(false);
    key = server.register(selector, SelectionKey.OP_WRITE);
    

    ...注意,如果超时到期,将引发异常。

实际上,我很少遇到在客户端中以非阻塞模式使用 NIO 有意义的情况。