Java 选择器 OP_READ 如果数据已经可用则不会触发

Java Selector OP_READ not triggered if data is already available

我正在编写一个接受连接的 NIO 服务器

serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

为了在接受连接和注册 OP_READ 之间创建竞争条件,让我们假设接受后,服务器等待 Thread.sleep(1000); 然后只注册读取

clientSocketChannel.register(selector, SelectionKey.OP_READ);

同时,由于延迟,一些客户端数据已经通过网络发送并且可用。

我遇到的是选择器不会触发 OP_READ 此现有数据,我必须手动强制读取。 OP_READ 然后为所有后续传入数据正确触发。

这是正常行为吗?尽管有一些数据准备好读取,但为什么它不触发?

Selector(和 SelectableChannel)的 javadoc 解释说 select() 调用 "have become selectable since the previous selection operation" 的频道,这对我来说意味着如果没有以前的 select离子操作它检查自注册以来的时间段,而不是之前。这意味着,是的,您看到的是预期的行为。

这也是合乎逻辑的 - 没有在 reads 中注册兴趣的频道没有理由跟踪传入数据,只有当你注册这样的兴趣时(即,在你注册 selector for OP_READ),它开始监视传入数据。

底线是 - 您可能想要注册 select 或立即注册,而不是等待一秒钟再注册。

如果在收到 OP_ACCEPT 事件后你做了类似的事情:

SocketChannel client = serverSocket.accept();
client.configureBlocking(false);
client.register(selector, SelectionKey.OP_READ);

你参加比赛的机会非常小,因为另一端必须:

  1. 找出接受的连接(涉及网络跃点),
  2. 向套接字写入一些数据,
  3. 数据必须通过网络,

以及您两次调用 accept() 和 register() 之间的所有操作,none 其中涉及通过网络传输数据。我非常怀疑在两者之间获取(完整的)数据是否现实(注意:它应该是一个完整的数据,否则其中一些会在注册后出现,因此会触发 select)。