Skip to content
Advertisement

Why ‘java.net.SocketException: Socket closed’ after ‘java.net.ConnectException: Connection refused’?

I’m trying to connect to a remote host trying over and over waiting for it to come up. However, after one shot with a Connection Refused exception (because the server isn’t running yet), it throws Socket closed exception continuously. Why would the socket be closed? The socket should simply be in the same state as it was before the failed connect() call, shouldn’t it?

                while(!tcpSock.isConnected()) {
                    try {
                        tcpSock.connect(destination);
                    } catch (SocketException e) {
                        System.err.println(e.toString());
                    }
                }

results in

Setting TCP client mode connecting to remote host localhost/127.0.0.1 port 4500
java.net.ConnectException: Connection refused: connect
java.net.SocketException: Socket closed
java.net.SocketException: Socket closed
java.net.SocketException: Socket closed
java.net.SocketException: Socket closed

Desired behavior is

Setting TCP client mode connecting to remote host localhost/127.0.0.1 port 4500
java.net.ConnectException: Connection refused: connect
java.net.ConnectException: Connection refused: connect
java.net.ConnectException: Connection refused: connect
java.net.ConnectException: Connection refused: connect
Established connection to: localhost port 4500

(Once I’m done debugging, I’ll comment out the print of the exception.)

Advertisement

Answer

Looking at the OpenJDK source code … when the connect(...) call fails, the SocketImpl code calls close() on the Socket.

This is the code in Java 11 (in java.net.AbstractPlainSocketImpl):

protected void connect(String host, int port)
    throws UnknownHostException, IOException
{
    boolean connected = false;
    try {
        InetAddress address = InetAddress.getByName(host);
        this.port = port;
        this.address = address;

        connectToAddress(address, port, timeout);
        connected = true;
    } finally {
        if (!connected) {
            try {
                close();  // <<---- HERE
            } catch (IOException ioe) {
                /* Do nothing. If connect threw an exception then
                   it will be passed up the call stack */
            }
        }
    }
}

That close() call on the SocketImpl object leads to the Socket being marked as closed.


In short, a Java Socket object does not support retrying after a failed connection attempt. If you want to retry, your code needs to create a new Socket object.

Discussion of whether it is correct for Socket to behave this way is beside the point. It just does … and it is highly unlikely that this will ever change. The only thing that might change is that they might document this behavior in the Socket javadocs.

User contributions licensed under: CC BY-SA
4 People found this is helpful
Advertisement