Java NIO select()返回没有选中的键 – 为什么?

在编写一些测试代码时,我发现Selector.select()可以在没有Selector.selectedKeys()的情况下返回,其中包含要处理的任何键。 当我注册一个accept()ed频道时,会发生这种情况

  SelectionKey.OP_READ |  SelectionKey.OP_CONNECT 

作为感兴趣的业务。

根据文档,select()应该在以下时间返回:

1)有可以采取行动的渠道。

2)您明确调用Selector.wakeup() – 未选择任何键。

3)显式Thread.interrupt()执行select()的线程 – 没有选择键。

如果我在select()之后没有键,我必须在case(2)和(3)中。 但是,我的代码不是调用wakeup()或interrupt()来启动这些返回。

关于是什么导致这种行为的任何想法?

简短回答:从您感兴趣的接受连接操作列表中删除OP_CONNECT – 已连接已接受的连接。

我设法重现了这个问题,这可能正是你发生的事情:

 import java.net.*; import java.nio.channels.*; public class MyNioServer { public static void main(String[] params) throws Exception { final ServerSocketChannel serverChannel = ServerSocketChannel.open(); serverChannel.configureBlocking(true); serverChannel.socket().bind(new InetSocketAddress("localhost", 12345)); System.out.println("Listening for incoming connections"); final SocketChannel clientChannel = serverChannel.accept(); System.out.println("Accepted connection: " + clientChannel); final Selector selector = Selector.open(); clientChannel.configureBlocking(false); final SelectionKey clientKey = clientChannel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_CONNECT); System.out.println("Selecting..."); System.out.println(selector.select()); System.out.println(selector.selectedKeys().size()); System.out.println(clientKey.readyOps()); } } 

在上述服务器收到连接后,连接上的第一个select()在没有阻塞的情况下退出,并且没有带有就绪操作的密钥。 我不知道为什么Java会以这种方式表现,但似乎很多人都被这种行为所困扰。

Windows XP上Sun的JVM 1.5.0_06以及Linux 2.6上的Sun的JVM 1.5.0_05和1.4.2_04的结果是相同的。

原因是OP_CONNECTOP_WRITE是相同的东西,所以你永远不应该同时注册(同样OP_ACCEPTOP_READ ),并且当频道已经连接时你根本不应该注册OP_CONNECT ,因为它在这种情况下,已被接受。

并且OP_WRITE几乎总是准备就绪,除非e内核中的套接字发送缓冲区已满,所以只有在获得零长度写入后才应该注册。 因此,通过为OP_CONNECT,注册已连接的通道OP_CONNECT,您实际上正在注册OP_WRITE,OP_WRITE,已准备好,因此select()被触发。