Java 注册多重选择键

Java 注册多重选择键,java,nio,channel,Java,Nio,Channel,我正在NIO中使用Java选择器。我正在向特定频道和选择器注册我的选择密钥/兴趣密钥。现在,我的要求是为一个特定选择器设置两个或多个兴趣集 我所做的是制作两个具有不同选择选项的SelectionKey,如下所示: try { Selector selector = Selector.open(); ServerSocketChannel channel = ServerSocketChannel.open(); //FileChannel

我正在NIO中使用Java选择器。我正在向特定频道和选择器注册我的选择密钥/兴趣密钥。现在,我的要求是为一个特定选择器设置两个或多个兴趣集

我所做的是制作两个具有不同选择选项的SelectionKey,如下所示:

    try {
        Selector selector = Selector.open();
        ServerSocketChannel channel = ServerSocketChannel.open();
        //FileChannel channel = new FileInputStream("").getChannel();

        channel.configureBlocking(false);

        SelectionKey key1 = channel.register(selector, SelectionKey.OP_READ);
        SelectionKey key2 = channel.register(selector, SelectionKey.OP_WRITE);

    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

我的问题是,有什么方法可以避免生成两个不同的键吗?

您可以将两个键或两个键组合在一起以创建一个单独的兴趣:

SelectionKey key = channel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);

您可以将二进制或键组合在一起创建单个兴趣:

SelectionKey key = channel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);

不过,一个老问题需要注意

请注意,在同一频道上调用
register
两次不会添加额外的注册,而是会替换上一个注册

OP提出的代码有几个值得注意的问题:

try {
    Selector selector = Selector.open();
    ServerSocketChannel channel = ServerSocketChannel.open();

    channel.configureBlocking(false);

    //====================================================================
    // NOTE:
    // this is not good - see notes below...
    //====================================================================

    SelectionKey key1 = channel.register(selector, SelectionKey.OP_READ);
    SelectionKey key2 = channel.register(selector, SelectionKey.OP_WRITE);

    //====================================================================

    // NOTE 1:
    // the 2nd call to channel.register causes the channel to be registered
    // only for OP_WRITE, replacing the registration for OP_READ.
    // So both lines together makes the first one redundant 'dead code'.

    // NOTE 2:
    // the key returned in both calls would be the same as the key is
    // associated with the channel, regardless of the events we register for 
    // (changing the registration doesn't change the SelectionKey, it only
    // sets another registration for this key).

    // NOTE 3:
    // ServerSocketChannel should not be registered for OP_READ, OP_WRITE...
    // ServerSocketChannel should be registered for OP_ACCEPT
    // You may register SocketChannel to OP_READ and OP_WRITE

    //====================================================================

} catch (IOException e) { // ...
因此,如前所述,正确的方法是使用按位或,并进行以下附加修复:

    SocketChannel clientChannel = serverSockChannel.accept();
    clientChannel.configureBlocking(false);
    SelectionKey key =
      clientChannel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);

这不仅仅是注册两个事件的更好方法--否则它不起作用

一个老问题,尽管需要注意

请注意,在同一频道上调用
register
两次不会添加额外的注册,而是会替换上一个注册

OP提出的代码有几个值得注意的问题:

try {
    Selector selector = Selector.open();
    ServerSocketChannel channel = ServerSocketChannel.open();

    channel.configureBlocking(false);

    //====================================================================
    // NOTE:
    // this is not good - see notes below...
    //====================================================================

    SelectionKey key1 = channel.register(selector, SelectionKey.OP_READ);
    SelectionKey key2 = channel.register(selector, SelectionKey.OP_WRITE);

    //====================================================================

    // NOTE 1:
    // the 2nd call to channel.register causes the channel to be registered
    // only for OP_WRITE, replacing the registration for OP_READ.
    // So both lines together makes the first one redundant 'dead code'.

    // NOTE 2:
    // the key returned in both calls would be the same as the key is
    // associated with the channel, regardless of the events we register for 
    // (changing the registration doesn't change the SelectionKey, it only
    // sets another registration for this key).

    // NOTE 3:
    // ServerSocketChannel should not be registered for OP_READ, OP_WRITE...
    // ServerSocketChannel should be registered for OP_ACCEPT
    // You may register SocketChannel to OP_READ and OP_WRITE

    //====================================================================

} catch (IOException e) { // ...
因此,如前所述,正确的方法是使用按位或,并进行以下附加修复:

    SocketChannel clientChannel = serverSockChannel.accept();
    clientChannel.configureBlocking(false);
    SelectionKey key =
      clientChannel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
这不仅仅是注册两个事件的更好方法--否则它不起作用

更常见的名称是“按位或”,更常见的名称是“按位或”