sph*_*nks 3 java nio socketchannel
我有一个简单的非阻塞服务器与主循环:
try {
while (selector.select() > -1) {
// Wait for an event one of the registered channels
// Iterate over the set of keys for which events are available
Iterator selectedKeys = selector.selectedKeys().iterator();
while (selectedKeys.hasNext()) {
SelectionKey key = (SelectionKey) selectedKeys.next();
selectedKeys.remove();
try {
if (!key.isValid()) {
continue;
}
if (key.isConnectable()) {
connect(key);
}
// Check what event is available and deal with it
if (key.isAcceptable()) {
accept(key);
}
if (key.isReadable()) {
read(key);
}
if (key.isWritable()) {
write(key);
}
} catch (Exception e) {
e.printStackTrace();
close(key);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
Run Code Online (Sandbox Code Playgroud)
在读/写部分,我检查是否有东西要读/写 - 如果没有 - 然后我尝试关闭通道:
if (channel.read(attachment.buffer) < 1)
close(key);
Run Code Online (Sandbox Code Playgroud)
关闭方法:
private void close(SelectionKey key) throws IOException {
key.cancel();
key.channel().close();
}
Run Code Online (Sandbox Code Playgroud)
但是在处理这段代码的过程中,我在主循环中得到了异常(它被捕获但我认为有些错误)我得到了这个堆栈跟踪:
java.nio.channels.CancelledKeyException
at sun.nio.ch.SelectionKeyImpl.ensureValid(Unknown Source)
at sun.nio.ch.SelectionKeyImpl.readyOps(Unknown Source)
at java.nio.channels.SelectionKey.isWritable(Unknown Source)
Run Code Online (Sandbox Code Playgroud)
因此,当进入写入部分,关闭通道并在"可写"部分中返回到主循环时,它在主循环上失败,并且失败并出现此类异常.有什么建议?
错误很简单.
if (!key.isValid()) {
continue;
}
if (key.isConnectable()) {
connect(key);
}
// Check what event is available and deal with it
if (key.isAcceptable()) {
accept(key);
}
if (key.isReadable()) {
read(key);
}
if (key.isWritable()) {
write(key);
}
Run Code Online (Sandbox Code Playgroud)
你的read
方法取消了SelectionKey
.但是,在返回之后read
,您再次测试通道是否可写的关键 - 可能在取消相同的键之后!您的初步检查在这里无济于事.
一种解决方案是检查密钥在可能被取消的任何地方是否有效:
...
if (key.isValid() && key.isWritable()) {
write(key);
}
...
Run Code Online (Sandbox Code Playgroud)
或者,您也可以尝试在任何特定频道上一次只注册一个兴趣,因此所有准备事件都是互斥的:
if (!key.isValid()) {
continue;
}
if (key.isConnectable()) {
connect(key);
} else if (key.isAcceptable()) {
accept(key);
} else if (key.isReadable()) {
read(key);
} else if (key.isWritable()) {
write(key);
}
Run Code Online (Sandbox Code Playgroud)
这在情况下可能是有益的; 作为一般的信道几乎总是写就绪,保持沿侧读准备在写就绪的兴趣可能保持Selector
环纺纱,这是更可能不理想.在大多数情况下,通常仅在底层套接字输出缓冲区已满时才注册写入就绪感兴趣.
作为旁注,知道SocketChannel.read
可以返回值< 1
而不会出错.
读操作可能不会填充缓冲区,实际上它根本不会读取任何字节.它是否这样做取决于渠道的性质和状态.例如,处于非阻塞模式的套接字通道不能读取比套接字输入缓冲区中立即可用的字节数;
此外,Selector.select
没有说明返回的任何内容< -1
表明它已关闭.
返回:已更新就绪操作集的键数(可能为零)
归档时间: |
|
查看次数: |
10345 次 |
最近记录: |