我会向地图中的所有用户发送消息。
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,data是一个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);
}
解决方案:
我现在无法回答我自己的问题,所以把它放在这里:
接受方法中的SelectionKey有点残障。我尝试用read方法中的新键替换它,它可以工作。所以在User类中我不再保留SelectionKey var,现在我保留了SocketChannel。 SocketChannel有keyFor方法,所以当我有选择器时我可以获得密钥
u.getChannel().keyFor(_selector).interestOps(SelectionKey.OP_WRITE);
答案 0 :(得分:3)
听起来可能完全符合记录:
<强>抛出强>
IllegalArgumentException
- 如果集合中的某个位与此键的通道支持的操作不对应,即set & ~(channel().validOps()) != 0
虽然很难知道为什么,但如果不了解有关该频道的更多信息,那么......
答案 1 :(得分:2)
我想说你的用户地图包含ServerSocketChannel以及接受的SocketChannels。您无法在ServerSocketChannel上设置OP_WRITE。
我不知道'残疾人'是什么意思。