首页 > 解决方案 > 为什么当我尝试 telnet 时选择方法立即返回 0?

问题描述

我不熟悉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 秒打印一次“无事件”。

但是当我尝试远程登录它并且它开始非常快地打印“无事件”时。似乎选择方法返回值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它,select方法返回1。

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

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

标签: javanio

解决方案


您在 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() 返回被更新的key的个数,可能为零。当您再次使用 telnet 连接时,您将提供一个可以更新的新密钥。如果您只有一个连接,则无需选择新频道来收听。因此,没有任何东西被切换。如果您有两个连接,那么每次都会修改其中一个是有意义的。


推荐阅读