0

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

在 2.2 select() 选择 1 个键,然后 finishConnect() 调用抛出异常。正如预期的那样。但它仅在第一行未注释时才有效(preferIPv6 = false)。

但是在 4.1.2 select() 总是返回零。并且选定的键集为空。检查值表示,选择键始终未准备好进行任何操作,interestOps 为 8 (OP_CONNECT)。

在 java connect() 调用中抛出 IOException: Network is unreachable。正如预期的那样。

我做错了什么以及如何导致 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);
}

谢谢。

4

2 回答 2

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

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

于 2013-08-12T14:25:42.497 回答
0

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

于 2013-08-13T01:09:23.990 回答