InterestOps бросает IllegalArgumentException - PullRequest
1 голос
/ 21 марта 2012

Я отправляю сообщение всем Пользователям на карте.

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

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

, но когда я запускаю эту функцию, я вижу

Исключение в теме "main" java.lang.IllegalArgumentException

эта строка делает ошибку

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

getKey () возвращает SelectionKey, getMessages возвращает ArrayList, данные представляют собой массив byte [] с сообщением, которое я прочитал с использованием channel.read (buffer);

ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ:

В конструкторе я делаю Selector

_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);
}

В функции чтения, когда я читаю сообщение, у меня есть это для каждого цикла.Но когда один пользователь и я перемещаю строку с интересами сразу за циклом, она работает.

        //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);
}

РЕШЕНИЕ:

Iсейчас я не могу ответить на свой вопрос, поэтому задайте его здесь:

SelectionKey в методе accept немного затруднен.Я попытался заменить его новым ключом в методе чтения, и он работает.Так что в классе User я больше не держу SelectionKey var, теперь я держу SocketChannel.У SocketChannel есть метод keyFor, поэтому, когда у меня есть селектор, я могу получить ключ

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

Ответы [ 2 ]

3 голосов
/ 21 марта 2012

Звучит так, как будто это точно так, как задокументировано:

Броски
IllegalArgumentException - Если бит в наборе не соответствует операции, которая поддерживаетсяканал этого ключа, то есть, если set & ~(channel().validOps()) != 0

Трудно понять , почему так и есть, не зная больше о рассматриваемом канале, хотя ...

2 голосов
/ 22 марта 2012

Я бы сказал, что ваша пользовательская карта содержит ServerSocketChannel, а также принятые SocketChannels.Вы не можете установить OP_WRITE для ServerSocketChannel.

Я не знаю, что вы подразумеваете под «инвалидом».

...