Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

java.net.SocketTimeoutException vs java.net.ConnectException

Tags:

java

sockets

When connecting to a server with a Java client socket I had this two different connection timeout exceptions.

Caused by: java.net.SocketTimeoutException: connect timed out
    at java.net.PlainSocketImpl.socketConnect(Native Method)
    at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:381) 

Caused by: java.net.ConnectException: Connection refused: connect 
    at java.net.PlainSocketImpl.socketConnect(Native Method) 
    at java.net.PlainSocketImpl.doConnect(Unknown Source) 

I checked the documentation but for SocketTimeoutException it's written that "Signals that a timeout has occurred on a socket read or accept", but this is not the situation in my case. Because I am getting it during connection establishment.

What is the difference between between these two exceptions? Actually I was expecting getting the ConnectException in any connection problem (firewall, port down, etc.)

like image 562
cacert Avatar asked Jun 09 '14 08:06

cacert


2 Answers

You will get a SocketTimeoutException if you specify a timeout on connect(), or if you've called setSoTimeout() on a Socket or ServerSocket and a read() or accept() times out, respectively. In the case of connect(), this is a serious problem: what you're trying to connect to either doesn't exist or is behind a firewall, and you can't tell which.

You will get connection refused if the peer actively refused your connection request, which usually means there is nothing listening at the port you specified. Note that unlike a timeout, this means a response was received, and it was negative.

like image 145
user207421 Avatar answered Oct 13 '22 14:10

user207421


Also came here looking for the same answer, seemingly the docs can be easily misinterpreted:

Connects this socket to the server with a specified timeout value. A timeout of zero is interpreted as an infinite timeout. The connection will then block until established or an error occurs.

The key part that I overlooked in this is "an error"... going to the source I can see how Java's connect() is actually invoking the Linux connect():

if (timeout <= 0) {
    connect = connect(args...);
    if (connect == -1 && errno == EINPROGRESS) {
        connect = poll(args...);
        // try again on EINTR
    }
} else {
    // Go to non-blocking mode for a timeout.
    connect = connect(args...);

    if (connect!=0) {
        // not EINPROGRESS? -> throw ConnectException
        while (!connect || !error || timedout) {
            connect = poll(args...);
            // error / timedout handling
        }
        if (timedout) {
            // throw SocketTimeoutException
        }
    }
}

/* report the appropriate exception */
if (error) {
    //EINVAL; throw SocketException
    //EINTR; throw InterruptedIOException
    //EPROTO; throw ProtocolException
    //ECONNREFUSED;ETIMEDOUT; throw ConnectException
    //EHOSTUNREACH; throw NoRouteToHostException
    //EADDRNOTAVAIL; throw NoRouteToHostException
    //EISCONN, EBADF, other; throw SocketException
}

i.e. I think SocketTimeoutException is being thrown when the network is slow, or the host doesn't respond at all. Checking man connect, I can see that ECCONNREFUSED must be thrown when "No-one listening on the remote address", i.e. and an ICMP tells us so.

This means that if like me, you were trying to use the timeout to connect to a (localhost) socket that wasn't ready to be connected to, you are SOL'd.

like image 43
Alun Avatar answered Oct 13 '22 13:10

Alun