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.