gpt4 book ai didi

java - 修复太多打开的文件异常(我正在使用 try-catch-finally)

转载 作者:IT王子 更新时间:2023-10-29 00:37:08 27 4
gpt4 key购买 nike

我有一个用 JAVA(1.8 版)编写的 Web 服务,它连接 HSM 并通过套接字发送/接收数据。我的应用程序部署在 linux 上的 Apache Tomcat/8.5.14 上。

虽然我正在正确关闭套接字连接,但我有

java.net.SocketException: Too many open files

这是我的类(class)

public class myClass implements AutoCloseable {
Socket socket;
DataInputStream in;
DataOutputStream out;

public myClass(String ip, int port) throws Exception {
try {
socket = new Socket(ip, port);
in = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
out = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
} catch (IOException e) {
throw new Exception("Connecting to HSM failed" + e);
}
}

public String sendCommandToHsm(String command) throws IOException {
out.writeUTF(command);
out.flush();
return in.readUTF();
}

@Override
public void close() {
if (socket != null && !socket.isClosed()) {
try {
socket.close();
} catch (IOException e) {
lgg.info("Closing of socket failed", e);
}
}

if (in != null) {
try {
in.close();
} catch (IOException e) {
lgg.info("Closing of inputStream failed", e);
}
}

if (out != null) {
try {
out.close();
} catch (IOException e) {
lgg.info("Closing of outputStream failed", e);
}
}
}

}

这是我类(class)的使用

try (MyClass myClass = new MyClass(ip, port);) {
myClass.sendCommandToHsm("my command");
}

我将服务器上的最大打开文件限制从默认值 (1024) 增加到 8192,但几次之后同样的Exception 再次发生。

我正在考虑创建套接字连接池,这是个好主意吗?

您能推荐任何其他解决方案吗?

最佳答案

Although I'm closing socket connection properly ...

看起来你是,但我认为有几个问题。 (我不知道这些是你泄漏的原因,但第一个是一个合理的解释。)

问题1.

public myClass(String ip, int port) throws Exception {
try {
socket = new Socket(ip, port);
in = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
out = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
} catch (IOException e) {
throw new Exception("Connecting to HSM failed" + e);
}
}

如果在设置流期间抛出异常,则套接字将泄漏。

问题2.

public void close() {
if (socket != null && !socket.isClosed()) {
try {
socket.close();
} catch (IOException e) {
lgg.info("Closing of socket failed", e);
}
}

if (in != null) {
try {
in.close();
} catch (IOException e) {
lgg.info("Closing of inputStream failed", e);
}
}

if (out != null) {
try {
out.close();
} catch (IOException e) {
lgg.info("Closing of outputStream failed", e);
}
}
}

您关闭的顺序错误。在关闭socket 之前,您应该1 关闭inout。特别是,如果 out 有缓冲数据,那么关闭 out 将尝试刷新...如果您已经关闭了 socket,这将失败。

此外,如果 socket.close()in.close() 由于除 IOException 之外的其他原因而失败,则后续关闭将被跳过。所以你应该在这里使用 finally

isClosed() 调用也是多余的。在已经关闭的资源上调用 close() 应该什么都不做。这是 close() 契约的一部分。

最后,在套接字上调用close() 应该2 自动关闭inout 下的低级文件描述符。所以可以说最好只这样做:

public void close() {
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
lgg.info("Closing of socket failed", e);
}
}
}

如果这不能修复您的泄漏,我建议您使用 netstatlsof 来尝试查明泄漏是打开的文件还是打开的套接字。


I'm thinking about creating Socket Connection Pool, is it good idea?

是的...如果您能找到满足您要求的现有(设计和测试良好的)库。从头开始实现可靠的矿池并非易事。

但注意:

  1. 错误实现(或使用)的池可能会泄漏文件描述符。
  2. 服务器端需要能够在同一个连接上处理一系列请求/回复。
  3. 如果您有太多同时打开的连接到不同的地方,那么池需要一种方法来关闭其中的一些...

1 - 是否应该在 in 之前关闭 out 值得商榷。一方面,关闭 out 会将未完成的数据刷新到服务器。另一方面,在调用 myClass.close() 时,不会有任何内容读取服务器的响应。此外,sendCommandToHsm 方法会刷新...因此不应有任何未完成的数据。

2 - Socket.close() 的 javadoc 说:“关闭此套接字也会关闭套接字的 InputStreamOutputStream 。”

关于java - 修复太多打开的文件异常(我正在使用 try-catch-finally),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47635910/

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