修复太多打开的文件异常(我正在使用 try-catch-finally)
Fixing too many open files Exception(I am using try-catch-finally)
我在 JAVA(1.8 版)上编写了 Web 服务,它通过套接字连接 HSM 和 sends/receives 数据。我的应用程序部署在 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
再次发生。
我正在考虑创建 Socket Connection Pool
,这是个好主意吗?
你能提出任何其他解决方案吗?
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 关闭 in
和 out
。特别是,如果 out
有缓冲数据,则关闭 out
将尝试刷新...如果您已经关闭 socket
,这将失败。
此外,如果 socket.close()
或 in.close()
由于 IOException
以外的其他原因失败,则将跳过后续关闭。所以你应该在这里使用finally
。
此外,isClosed()
调用是多余的。在已经关闭的资源上调用 close()
应该什么都不做。这是 close()
合同的一部分。
最后,在套接字上调用 close()
应该2 自动关闭 in
和 out
下的低级文件描述符。所以可以说最好只这样做:
public void close() {
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
lgg.info("Closing of socket failed", e);
}
}
}
如果这不能解决您的泄漏,我建议您使用 netstat
和 lsof
来尝试找出泄漏是打开的文件还是打开的套接字。
I'm thinking about creating Socket Connection Pool, is it good idea?
是的...如果您能找到满足您要求的现有(设计和测试良好的)库。从头开始实施可靠的矿池并非易事。
但注意:
- 未正确实施(或使用)的池可能会泄漏文件描述符。
- 服务器端需要能够在同一个连接上处理一系列请求/回复。
- 如果您有太多同时打开的连接到不同的 地方,那么池需要一种方法来关闭其中的一些...
1 - 是否应该在 in
之前关闭 out
是有争议的。一方面,关闭 out
会将未完成的数据刷新到服务器。另一方面,在 myClass.close()
被调用时,不会有任何内容读取服务器的响应。此外,sendCommandToHsm
方法会刷新...因此不应有任何未完成的数据。
2 - Socket.close()
的 javadoc 说:"Closing this socket will also close the socket's InputStream
and OutputStream
."
我在 JAVA(1.8 版)上编写了 Web 服务,它通过套接字连接 HSM 和 sends/receives 数据。我的应用程序部署在 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
再次发生。
我正在考虑创建 Socket Connection Pool
,这是个好主意吗?
你能提出任何其他解决方案吗?
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 关闭 in
和 out
。特别是,如果 out
有缓冲数据,则关闭 out
将尝试刷新...如果您已经关闭 socket
,这将失败。
此外,如果 socket.close()
或 in.close()
由于 IOException
以外的其他原因失败,则将跳过后续关闭。所以你应该在这里使用finally
。
此外,isClosed()
调用是多余的。在已经关闭的资源上调用 close()
应该什么都不做。这是 close()
合同的一部分。
最后,在套接字上调用 close()
应该2 自动关闭 in
和 out
下的低级文件描述符。所以可以说最好只这样做:
public void close() {
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
lgg.info("Closing of socket failed", e);
}
}
}
如果这不能解决您的泄漏,我建议您使用 netstat
和 lsof
来尝试找出泄漏是打开的文件还是打开的套接字。
I'm thinking about creating Socket Connection Pool, is it good idea?
是的...如果您能找到满足您要求的现有(设计和测试良好的)库。从头开始实施可靠的矿池并非易事。
但注意:
- 未正确实施(或使用)的池可能会泄漏文件描述符。
- 服务器端需要能够在同一个连接上处理一系列请求/回复。
- 如果您有太多同时打开的连接到不同的 地方,那么池需要一种方法来关闭其中的一些...
1 - 是否应该在 in
之前关闭 out
是有争议的。一方面,关闭 out
会将未完成的数据刷新到服务器。另一方面,在 myClass.close()
被调用时,不会有任何内容读取服务器的响应。此外,sendCommandToHsm
方法会刷新...因此不应有任何未完成的数据。
2 - Socket.close()
的 javadoc 说:"Closing this socket will also close the socket's InputStream
and OutputStream
."