Search code examples
javaandroidnio

Selector on Android sockets behaves strangely


Prerequisites: Android 2.2 emulator.

I have a perfectly working Java code which is compiled perfectly for Android as well. But there comes the strange part. In particular, it seems that java.nio.Selector doesn't work at all.

First problem arises during connection. The following code works on Java but doesn't work on Android (see below for details).

socketChannel.configureBlocking(false);
socketChannel.connect(new InetSocketAddress(remoteAddr, getRemotePort()));

Selector selector = Selector.open();
socketChannel.register(selector, socketChannel.validOps());

// Wait for an event
int selRes = selector.select(timeout); 
if (selRes == 1)
{
    SelectionKey selKey = (SelectionKey)selector.selectedKeys().iterator().next();
    if (selKey.isValid() && selKey.isConnectable()) {
        // Get channel with connection request
        boolean success = socketChannel.finishConnect();
        if (!success) {
            selKey.cancel();
        }
    }
}                   

I pass timeout of 30000 (msec, which is 30 sec), but select returns immediately with selres equal to 0 (on Desktop Java it's 1). Switching socket to blocking mode works fine (so addresses, ports and other stuff is ok).

Ok, I left connection to be blocking (for now). But now my Accept stopped working - Selector doesn't report incoming connections. Again, getting rid of Selector by using a blocking socket works.

So the question is -- does Selector work at all in Android or the code should be rewritten to avoid Selector and java.nio altogether?


Solution

  • The problem has a weird solution found in seemingly unrelated bug-report in Android bug tracker. Android Emulator doesn't support IPv6 and while I don't pretend to request IPv6, it seems that by default Selector attempts to work on IPv6 stack.

    Once the following lines are added, my code starts to work correctly:

    java.lang.System.setProperty("java.net.preferIPv4Stack", "true");
    java.lang.System.setProperty("java.net.preferIPv6Addresses", "false");