gpt4 book ai didi

java - 如何在 Java NIO 中正确关闭 SocketChannel?

转载 作者:塔克拉玛干 更新时间:2023-11-01 21:59:07 26 4
gpt4 key购买 nike

我有一个带有主循环的简单非阻塞服务器:

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

在读/写部分,我检查是否有可读/写的东西,如果没有 - 然后我尝试关闭 channel :

if (channel.read(attachment.buffer) < 1) 
close(key);

关闭方法:

private void close(SelectionKey key) throws IOException {
key.cancel();
key.channel().close();
}

但是在处理这段代码的过程中,我在主循环中遇到了异常(它被捕获了,但我认为出了点问题)我得到了这个堆栈跟踪:

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)

因此,当进入写入部分时,它在主循环上失败,关闭 channel 并在“可写”部分返回主循环,并因此类异常而失败。有什么建议吗?

最佳答案

错误很简单。

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

你的 read方法是取消 SelectionKey 的方法.然而,从read返回后,您再次测试 key 是否可写 channel - 可能是在刚刚取消同一个 key 之后!您的初步检查在这里无济于事。


一个解决方案是检查 key 是否有效,无论它是否刚刚被取消:

...
if (key.isValid() && key.isWritable()) {
write(key);
}
...

或者,您也可以根据需要在任何特定 channel 上一次只注册一个兴趣,因此所有就绪事件都是互斥的:

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

这在某些情况下可能是有益的;通常一个 channel 几乎总是写就绪,在读就绪的同时保持对写就绪的兴趣可能会保持 Selector循环旋转,这很可能是可取的。在大多数情况下,通常仅当底层套接字输出缓冲区已满时才对写入准备感兴趣。


作为旁注,知道 SocketChannel.read 可以返回一个值< 1而不是错误。

A read operation might not fill the buffer, and in fact it might not read any bytes at all. Whether or not it does so depends upon the nature and state of the channel. A socket channel in non-blocking mode, for example, cannot read any more bytes than are immediately available from the socket's input buffer;

此外, Selector.select 没有说明任何关于返回 < -1 的事情表示它已关闭。

Returns: The number of keys, possibly zero, whose ready-operation sets were updated

关于java - 如何在 Java NIO 中正确关闭 SocketChannel?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11854382/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com