在编写一些测试代码时,我发现Selector.select()可以在没有Selector.selectedKeys()的情况下返回,其中包含要处理的任何键。当我用

注册一个accept()ed频道时,会发生这种情况
SelectionKey.OP_READ | SelectionKey.OP_CONNECT

作为感兴趣的操作。

根据文档,select()应该在以下时间返回:

1)有些渠道可以采取行动。

2)你明确地调用了Selector.wakeup() - 没有选择任何键。

3)显式Thread.interrupt()执行select()的线程 - 没有选择键。

如果我在select()之后没有键,我必须在case(2)和(3)中。但是,我的代码不是调用wakeup()或interrupt()来启动这些返回。

有关导致此行为的原因的任何想法?

有帮助吗?

解决方案

简短回答:从您感兴趣的接受连接操作列表中删除 OP_CONNECT - 已接受已接受的连接。

我设法重现了这个问题,这可能正是你发生的事情:

import java.net.*;
import java.nio.channels.*;


public class MyNioServer {
  public static void main(String[] params) throws Exception {
    final ServerSocketChannel serverChannel = ServerSocketChannel.open();
    serverChannel.configureBlocking(true);
    serverChannel.socket().bind(new InetSocketAddress("localhost", 12345));
    System.out.println("Listening for incoming connections");
    final SocketChannel clientChannel = serverChannel.accept();
    System.out.println("Accepted connection: " + clientChannel);


    final Selector selector = Selector.open();
    clientChannel.configureBlocking(false);
    final SelectionKey clientKey = clientChannel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_CONNECT);
    System.out.println("Selecting...");
    System.out.println(selector.select());
    System.out.println(selector.selectedKeys().size());
    System.out.println(clientKey.readyOps());
  }
}

在上述服务器收到连接后,连接上的第一个 select()退出而没有阻塞,并且没有准备好操作的密钥。我不知道为什么Java会以这种方式表现,但似乎很多人都被这种行为所困扰。

Windows XP上Sun的JVM 1.5.0_06以及Linux 2.6上的Sun的JVM 1.5.0_05和1.4.2_04的结果是相同的。

其他提示

原因是 OP_CONNECT OP_WRITE 是同一件事,所以你永远不应该同时注册(同上 OP_ACCEPT OP_READ ),当频道已经连接时,你根本不应该注册 OP_CONNECT ,因为在这种情况下,它已被接受。

OP_WRITE 几乎总是准备就绪,除非e内核中的套接字发送缓冲区已满,所以只有在写入零长度后才能注册。因此,通过为 OP_CONNECT,注册已经连接的通道,您实际上已经注册了 OP_WRITE,,这已经准备就绪,因此 select()被触发。 / p>

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top