2

I have web service written on JAVA (version 1.8) which connects HSM and sends/receives data via socket. My application is deployed on Apache Tomcat/8.5.14 on linux.

Although I'm closing socket connection properly I have

java.net.SocketException: Too many open files

and here is myclass

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

}

Here is using of my class

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

I increased maximum open files limit on server from default value(1024) to 8192 and few times later the same Exception occurred again.

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

Can you suggest any other solutions?

JiboOne
  • 1,438
  • 4
  • 22
  • 55
Gog1nA
  • 376
  • 1
  • 8
  • 30
  • 5
    Possible duplicate of [Java Too Many Open Files](https://stackoverflow.com/questions/4289447/java-too-many-open-files) – xxxvodnikxxx Dec 04 '17 at 14:54
  • 4
    Don't forget that both files and sockets count for the ulimit. Don't have too many processes running on the same unix account, especially if they open many sockets. Check the limit with your OS command (I got that issue while running Weblogic on AIX, so you can't really reuse it) and where those sockets connect to using netstat or a similar tool. – Olivier Grégoire Dec 04 '17 at 14:57
  • Does your HSM really understand `writeUTF()`? Hard to believe. And why are you using a new connection per message? – user207421 Feb 11 '18 at 22:42

1 Answers1

3

Although I'm closing socket connection properly ...

It looks like you are, but I think there are a couple of problems. (I don't know that these are the cause of your leak, but the first one is a plausible explanation.)

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

If an exception is thrown during setup of the streams, then the socket will be leaked.

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

You are closing in the wrong order. You should1 close in and out before closing socket. In particular, if out has buffered data, then closing out will attempt to flush ... which will fail if you have closed socket already.

Also if socket.close() or in.close() fails for some other reason than an IOException, then the subsequent closes will be skipped. So you should use a finally here.

Also the isClosed() call is redundant. Calling close() on a resource that is already closed should do nothing. This is part of the contract of close().

Finally, calling close() on a socket should2 automatically close the low-level file descriptors beneath in and out. So it is arguably best to just do this:

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

If this doesn't fix your leaks, I suggest that you use netstat and lsof to try to find out if the leakage is open files or open sockets.


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

Yes ... if you can find an existing (well designed and tested) library that meets your requirements. Implementing a reliable pool from scratch is not trivial.

But note:

  1. An incorrectly implemented (or used) pool can leak file descriptors.
  2. The server-side needs to be able to cope with a series of requests / replied on the same connection.
  3. If you have too many simultaneous open connections to different places, then the pool needs a way to close some of them ...

1 - It is debatable whether you should close out before in. On the one hand, closing out flushes outstanding data to the server. On the other hand, by the time that myClass.close() has been called there won't be anything reading the server's response. And besides, the sendCommandToHsm method flushes ... so there shouldn't be any outstanding data.

2 - The javadoc for Socket.close() says: "Closing this socket will also close the socket's InputStream and OutputStream."

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • He should close `out` first, so it can be flushed, and `socket` in the `finally` block of that close. He need not close `in` at all. – user207421 Feb 11 '18 at 22:40
  • Assuming you are talking about his `close()` method, yes that is correct. – Stephen C Feb 11 '18 at 22:44
  • Well I'm really talking in a confused way about the `try` block enclosing `out.close()`. I'm specifically commenting on 'you should close `in` and `out`', which is at best back to front. – user207421 Feb 11 '18 at 22:52
  • Well, yeah, and if you completely understand the semantics of your application there isn't necessarily a need to close `in` *or* `out` either; just the socket. You can't have it both ways. *As a general rule*, which is what you seem to be stating, you should close the outermost stream or writer wrapped around the socket output stream. That way you can never be wrong. – user207421 Feb 12 '18 at 10:18