当没有网络时(在模拟器下),Java NIO select()在Android 4.1.2中返回0

时间:2013-08-12 13:39:10

标签: java android nio

我正在尝试使用Java NIO。一切都很好,直到我试图在模拟器无法访问互联网时测试连接。接下来是结果:

在2.2中select()选择1个键,然后在finishConnect()调用之后抛出异常。正如所料。但它仅在第一行未注释时才起作用(preferIPv6 = false)。

但是在4.1.2中,select()总是返回零。选定的键设置为空。检查值表示,该选择键始终没有为任何操作做好准备,interestOps为8(OP_CONNECT)。

在java connect()中调用throw IOException:网络无法访问。正如所料。

我做错了什么以及如何导致select()阻止?

//System.setProperty("java.net.preferIPv6Addresses", "false");

try {
    Selector selector = Selector.open();

    SocketChannel socketChannel = SocketChannel.open();

    socketChannel.configureBlocking(false);

    boolean connected = socketChannel.connect(new InetSocketAddress("173.194.44.3", 80));

    SelectionKey selectionKey;

    if (connected) {
        selectionKey = socketChannel.register(selector, SelectionKey.OP_READ);
    } else {
        selectionKey = socketChannel.register(selector, SelectionKey.OP_CONNECT);
    }

    while (true) {
        int selected = selector.select();

        if (selected == 0) continue;

        for (SelectionKey key : selector.selectedKeys()) {
            if (socketChannel.finishConnect()) {
                key.interestOps(SelectionKey.OP_READ);
            }
        }

        selector.selectedKeys().clear();
    }
} catch (IOException e) {
    throw new RuntimeException("IOException", e);
}

感谢。

2 个答案:

答案 0 :(得分:0)

问题看起来可以解决。

我添加了OP_READ兴趣和某些选择器选择键,准备好阅读。

但是当我试图阅读时,NotYetConnectedException抛出了。所以,我可以抓住这个并处理这个问题。然后,选择块。

但它看起来像虫子。

try {
    Selector selector = Selector.open();

    SocketChannel socketChannel = SocketChannel.open();

    socketChannel.configureBlocking(false);

    boolean connected = socketChannel.connect(new InetSocketAddress("173.194.44.3", 80));

    SelectionKey selectionKey;

    int validOps = socketChannel.validOps();

    if (connected) {
        selectionKey = socketChannel.register(selector, SelectionKey.OP_READ);
    } else {
        selectionKey = socketChannel.register(selector, SelectionKey.OP_CONNECT | SelectionKey.OP_READ);
    }

    ByteBuffer buffer = ByteBuffer.allocate(512);

    while (true) {
        int selected = selector.select();

        if (selected == 0) continue;

        for (SelectionKey key : selector.selectedKeys()) {
            SocketChannel sc = (SocketChannel) key.channel();

            if ((key.interestOps() & SelectionKey.OP_CONNECT) != 0 && key.isConnectable())
            {
                if (socketChannel.finishConnect()) {
                    key.interestOps(SelectionKey.OP_READ);
                }
            }

            if (key.isReadable()) {
                while (true) {
                    int readed = 0;

                    try {
                        readed = sc.read(buffer);
                    } catch (Exception e) {
                        sc.close();
                    }

                    if (readed == 0) break;

                    if (readed == -1) throw new RuntimeException("Closed");
                }
            }
        }

        selector.selectedKeys().clear();
    }
} catch (IOException e) {
    throw new RuntimeException("IOException", e);
}

也许这里存在更多“非魔法”解决方案?

答案 1 :(得分:0)

如果select()返回零,则某些内容已超时。您不应该只是继续,您应该将其视为错误或警告。例如,如果您选择等待OP_CONNECT触发60秒并且select()返回零,则应将其视为连接超时。