gpt4 book ai didi

java - 客户端突然与 Java NIO 断开连接后,服务器以 30% CPU 运行,我的修复是否有效?

转载 作者:行者123 更新时间:2023-12-01 11:29:33 25 4
gpt4 key购买 nike

我有一个我编写的非阻塞 NIO 服务器,在正常使用的情况下,它的大部分功能都按预期运行;但我注意到有时由于某种原因它的 CPU 使用率会停留在 30%。经过大量时间尝试强制执行该错误后,当我在接受 SocketChannel 后但在读取任何字节之前断开客户端连接时,最终触发了该错误。这纯粹是我偶然发现的。我花了一天的大部分时间试图捕获它,但没有成功。

似乎每隔几天左右就会发生一次。我添加了以下代码:

 SocketChannel channel = (SocketChannel) key.channel();             
if(!channel.isConnected()){
key.cancel();
break;
}

我当前的服务器循环现在看起来像这样:

    try {

Selector selector = Selector.open();
serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.configureBlocking(false);
ServerSocket serverSocket = serverSocketChannel.socket();
serverSocket.bind(new InetSocketAddress(serverPort));

log.info("Selector Thread: Server "
+ Server.SERVER_VERSION
+ " Runnable- Listening for connections on port: "
+ serverSocket.getLocalPort());

running = true;

@SuppressWarnings("unused")
SelectionKey serverAcceptKey = serverSocketChannel.register(
selector, SelectionKey.OP_ACCEPT);

while (running) {
selector.select();
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> keyIterator = selectedKeys.iterator();

while (keyIterator.hasNext()) {

SelectionKey key = (SelectionKey) keyIterator.next();
SocketChannel channel = (SocketChannel) key.channel();

if(!channel.isConnected()){
key.cancel();
break;
}
if ((key.readyOps() & SelectionKey.OP_ACCEPT) == SelectionKey.OP_ACCEPT) {

acceptConnection(selector, key);
keyIterator.remove();

} else if ((key.readyOps() & SelectionKey.OP_READ) == SelectionKey.OP_READ) {

readFromSocketChannel(key);
keyIterator.remove();

} else if ((key.readyOps() & SelectionKey.OP_WRITE) == SelectionKey.OP_WRITE) {

writeToSocketChannel(key);
keyIterator.remove();
}

}

}

} catch (IOException e) {
log.fatal(
"An IOException occurred, Selector or ServerSocket could not open, shutting down...",
e);
System.exit(-1);
}

}

在当前键的 channel 上添加 if 语句是否会捕获像我偶尔遇到的那样的突然断开连接?这些情况很少发生,并且不会由 OP_READ 在读取尝试时返回 -1 来处理,但它们似乎偶尔会发生。我的修复会起作用吗?

最佳答案

I've added the following code:

SocketChannel channel = (SocketChannel) key.channel();             
if(!channel.isConnected()){
key.cancel();
break;
}

毫无意义。当连接中断时,isConnected() 不会神奇地变为 false。它只会告诉您是否接受或连接了该 channel (您确实这样做了)。如果它确实神奇地为您提供了连接状态而不仅仅是 channel 状态,则您应该关闭该 channel 。不仅仅是取消 key 。

您应该将其替换为:

keyIterator.remove(); // unconditionally
if (!key.isValid())
continue; // key has been cancelled

并从所有其他位置删除keyIterator.remove()。也许这可以解决您的问题。否则,您将不得不发布更多代码,特别是从 channel 读取和写入 channel 的代码,以显示循环的位置。例如,如果您在执行任一操作时捕获 IOException,则必须关闭相关 channel :它已损坏。

关于java - 客户端突然与 Java NIO 断开连接后,服务器以 30% CPU 运行,我的修复是否有效?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30522321/

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