【问题标题】:interestOps throws IllegalArgumentExceptioninterestOps 抛出 IllegalArgumentException
【发布时间】:2012-03-21 17:50:03
【问题描述】:

我想向地图中的所有用户发送一条消息。

    for (User u : _userMap.values()) {
        u.getMessages().add(data);

        u.getKey().interestOps(SelectionKey.OP_WRITE);
    }

但是当我运行这个函数时,我看到了

线程“主”java.lang.IllegalArgumentException 中的异常

这一行出错

u.getKey().interestOps(SelectionKey.OP_WRITE);

getKey() 返回 SelectionKey,getMessages 返回 ArrayList,data 是一个 byte[] 数组,其中包含我使用 channel.read(buffer) 读取的消息;

更多信息:

在构造函数中我创建选择器

_selector = Selector.open();

我运行服务器

public void startServer() throws IOException {
    while (true) {
        _selector.select();

        Iterator<SelectionKey> keys = _selector.selectedKeys().iterator();

        while (keys.hasNext()) {
            SelectionKey key = keys.next();
            keys.remove();

            if (!key.isValid()) 
                continue;
            if (key.isAcceptable())
                accept(key);
            else if (key.isReadable())
                read(key);
            else if (key.isWritable())
                write(key);
        }
    }
}

我接受连接

private void accept(SelectionKey key) throws IOException {
    ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel(); 
    SocketChannel channel = serverChannel.accept();
    channel.configureBlocking(false);

    User u = new User(key);
    _userMap.put(channel, u);

    channel.register(_selector, SelectionKey.OP_READ);
}

在读取消息时,我在每个循环中都有这个。但是当我是一个用户并且我在循环后面使用interestOps 时,它可以工作。

        //u.getKey().interestOps(SelectionKey.OP_WRITE);
    }
    key.interestOps(SelectionKey.OP_WRITE);

完整的读写功能:

private void read(SelectionKey key) throws IOException {
    SocketChannel channel = (SocketChannel) key.channel();

    ByteBuffer buffer = ByteBuffer.allocate(2048);
    int read = -1;

    try {
        read = channel.read(buffer);
    } catch (Exception e) {
        e.printStackTrace();
    }

    if (read == -1) {
        _userMap.remove(channel);

        channel.close();
        key.cancel();

        return;
    }

    byte[] data = new byte[read];

    System.arraycopy(buffer.array(), 0, data, 0, read);

    /// WYSyŁA DO WSZYSTKICH. usunąć

    for (User u : _userMap.values()) {
        u.getMessages().add(data);

        u.getKey().interestOps(SelectionKey.OP_WRITE);
    }
    //key.interestOps(SelectionKey.OP_WRITE);

    ///////
}

private void write(SelectionKey key) throws IOException {
    SocketChannel channel = (SocketChannel) key.channel();

    ArrayList<byte[]> msg = _userMap.get(channel).getMessages();
    Iterator<byte[]> i = msg.iterator();

    while (i.hasNext()) {
        byte[] item = i.next();
        i.remove();

        channel.write(ByteBuffer.wrap(item));
    }

    key.interestOps(SelectionKey.OP_READ);
}

解决方案:

我现在无法回答我自己的问题,所以把它放在这里:

accept 方法中的SelectionKey 有点障碍。我试图用读取方法中的新密钥替换它并且它有效。所以在 User 类中我不再保留 SelectionKey var,现在我保留 SocketChannel。 SocketChannel 有 keyFor 方法,所以当我有选择器时,我可以得到 key

        u.getChannel().keyFor(_selector).interestOps(SelectionKey.OP_WRITE);

【问题讨论】:

标签: java nio


【解决方案1】:

听起来可能和记录的完全一样:

抛出
IllegalArgumentException - 如果集合中的某个位不对应此密钥通道支持的操作,即如果set &amp; ~(channel().validOps()) != 0

如果不了解有关频道的更多信息,很难知道为什么会出现这种情况......

【讨论】:

    【解决方案2】:

    我会说您的用户映射包含 ServerSocketChannel 以及接受的 SocketChannel。您不能在 ServerSocketChannel 上设置 OP_WRITE。

    我不知道你所说的“残障”是什么意思。

    【讨论】:

      猜你喜欢
      • 2014-09-18
      • 2014-11-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-18
      相关资源
      最近更新 更多