java.net.SocketTimeoutException vs java.net.ConnectException

cac*_*ert 9 java sockets

当连接到具有Java客户端套接字的服务器时,我有两个不同的连接超时异常.

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) 
Run Code Online (Sandbox Code Playgroud)

我检查了文档但是因为SocketTimeoutException它写了"表示在套接字读取或接受时发生了超时",但这不是我的情况.因为我在连接建立期间得到它.

这两个例外有什么区别?实际上我期待得到ConnectException任何连接问题(防火墙,端口关闭等)

Alu*_*lun 5

也来到这里寻找相同的答案,似乎文档很容易被误解:

将此套接字连接到具有指定超时值的服务器。零超时被解释为无限超时。然后连接将阻塞,直到建立或发生错误。

我在这方面忽略的关键部分是“错误”......转到源代码我可以看到 Javaconnect()是如何实际调用 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
}
Run Code Online (Sandbox Code Playgroud)

即我认为SocketTimeoutException是在网络缓慢或主机根本没有响应时被抛出。检查man connect,我可以看到ECCONNREFUSED必须在“无人侦听远程地址”时抛出,即 ICMP 告诉我们。

这意味着,如果像我一样,您尝试使用timeout连接到尚未准备好连接的(本地主机)套接字,那么您就是 SOL'd。


Pph*_*nix 1

ConnectException 在数据包过滤器/防火墙等上抛出。

当您在套接字上设置了特定的超时,并且在超时之前它没有收到任何内容时,会抛出 SocketTimeoutException 。

示例ServerSocket

ServerSocket serverSocket = new ServerSocket... // Create server socket
serverSocket.setSoTimeout(1000);  
serverSocket.accept();
Run Code Online (Sandbox Code Playgroud)

如果ServerSocket在 1000 毫秒内没有收到任何内容,它将抛出一个SocketTimeoutException. 请注意,所有使用超时的套接字都会引发此异常,而不仅仅是ServerSocket. 这意味着Socket抛出 a 的对象SocketTimeoutException在超时之前没有从被调用的服务器返回任何内容。

要解决此问题,您可以确保服务器响应更快,或设置更高的超时值。