Search code examples
javaselectnio

Java NIO select() returns without selected keys - why?


In writing some test code I have found that Selector.select() can return without Selector.selectedKeys() containing any keys to process. This is happening in a tight loop when I register an accept()ed channel with

SelectionKey.OP_READ | SelectionKey.OP_CONNECT

as the operations of interest.

According to the docs, select() should return when:

1) There are channels that can be acted upon.

2) You explicitly call Selector.wakeup() - no keys are selected.

3) You explicitly Thread.interrupt() the thread doing the select() - no keys are selected.

If I get no keys after the select() I must be in cases (2) and (3). However, my code is not calling wakeup() or interrupt() to initiate these returns.

Any ideas as to what is causing this behaviour?


Solution

  • Short answer: remove OP_CONNECT from the list of operations you are interested in for the accepted connection -- an accepted connection is already connected.

    I managed to reproduce the issue, which might be exactly what's happening to you:

    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());
      }
    }
    

    After the above server receives a connection, the very first select() on the connection exits without blocking and there are no keys with ready operations. I don't know why Java behaves in this way, but it appears many people get bitten by this behavior.

    The outcome is the same on Sun's JVM 1.5.0_06 on Windows XP as well as Sun's JVM 1.5.0_05 and 1.4.2_04 on Linux 2.6.