为什么在尝试远程登录时select方法立即返回0?

时间:2019-05-31 01:34:47

标签: java nio

我对Java Nio不熟悉。我试图写一个像这样的小样:

    ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
    serverSocketChannel.bind(new InetSocketAddress(9999)).configureBlocking(false);
    serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

    for (; ; ) {
        int select = selector.select(2_000);
        if (select == 0) {
            System.out.println("no event");
            continue;
        }
        System.out.println("select = " + select);
   }

超时设置为2秒,程序每2秒打印“无事件”。

但是当我尝试远程登录时,它开始非常快速地打印“无事件”。似乎select方法返回值0却没有被阻塞。

为什么?这是第一个问题。

当我试图在for循环中添加一些逻辑时,如下所示:

for (; ; ) {
            int select = selector.select();
            if (select == 0) {
                System.out.println("no event");
                continue;
            }
            System.out.println("select = " + select);
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
            System.out.println("iterator = " + iterator.hasNext());
            while (iterator.hasNext()) {
                SelectionKey key = iterator.next();
                iterator.remove();
            }
        }

然后我再次进行telnet,选择方法返回1。

为什么?这是第二个问题。

第一次在这里提问。请原谅我的英语不好。

1 个答案:

答案 0 :(得分:1)

您在select(long)中提供的数字与Thread.sleep(long)不同。根据:

https://docs.oracle.com/javase/7/docs/api/java/nio/channels/Selector.html#select(long)

select是一项阻止操作,但只要能够选择频道,它就会继续进行。因此,当您连接时,它将不断循环并输出。您提供的long值是告诉select(long)方法何时放弃尝试选择一个通道,无论如何不要休眠线程。为了保证至少2秒钟的睡眠,您需要在循环结束之前添加Thread.sleep(2000)。

对于返回值,select()返回已更新的键的数量,可以为零。当您再次与telnet连接时,您将提供一个可以更新的新密钥。如果只有一个连接,则无需选择新的频道进行收听。因此,什么都不会切换。如果您有两个连接,则每次都修改其中一个是有意义的。