问题
I wand send a message to all User in map.
for (User u : _userMap.values()) {
u.getMessages().add(data);
u.getKey().interestOps(SelectionKey.OP_WRITE);
}
but whene I run this function I see
Exception in thread "main" java.lang.IllegalArgumentException
this line make error
u.getKey().interestOps(SelectionKey.OP_WRITE);
getKey() returns SelectionKey, getMessages returns ArrayList, data is a byte[] array with message I read using channel.read(buffer);
MORE INFO:
In a constructor I make Selector
_selector = Selector.open();
I run server
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);
}
}
}
I accept connection
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);
}
In read function whene I read message I have this for each loop. But whene is one user and I move line with interestOps just behind loop it works.
//u.getKey().interestOps(SelectionKey.OP_WRITE);
}
key.interestOps(SelectionKey.OP_WRITE);
Full read and write function:
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);
}
SOLUTION:
I can't answer my own question now, so put it here:
SelectionKey in accept method is a little handicapped. I tried to replace it with new key in read method and it works. So in User class I don't keep SelectionKey var any more, now I keep SocketChannel. SocketChannel have keyFor method, so whene I have selector I can get key
u.getChannel().keyFor(_selector).interestOps(SelectionKey.OP_WRITE);
回答1:
Sounds like it's probably exactly as documented:
Throws
IllegalArgumentException
- If a bit in the set does not correspond to an operation that is supported by this key's channel, that is, ifset & ~(channel().validOps()) != 0
It's hard to know why that's the case without knowing more about the channel in question though...
回答2:
I would say your user map contains the ServerSocketChannel as well as accepted SocketChannels. You can't set OP_WRITE on a ServerSocketChannel.
I don't know what you mean by 'handicapped'.
来源:https://stackoverflow.com/questions/9810087/interestops-throws-illegalargumentexception