Question

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?

Was it helpful?

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.

OTHER TIPS

The reason is that OP_CONNECT and OP_WRITE are the same thing under the hood, so you should never be registered for both simultaneously (ditto OP_ACCEPT and OP_READ), and you should never be registered for OP_CONNECT at all when the channel is already connected, as it is in this case, having been accepted.

And OP_WRITE is almost always ready, except when the socket send buffer in e kernel is full, so you should only register for that after you get a zero length write. So by registering the already connected channel for OP_CONNECT, you were really registering for OP_WRITE, which was ready, so select() got triggered.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top