java.net.SocketTimeoutException vs java.net.ConnectException

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

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) 

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

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

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

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

我在这里忽略的关键部分是“错误”……转到源代码我可以看到Java的connect()实际上是如何调用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 } 

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

这意味着如果像我一样,你试图使用timeout连接到一个尚未准备连接的(localhost)套接字,那么你就是SOL’d。

在包filter/防火墙等上抛出ConnectException。

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

ServerSocket示例:

 ServerSocket serverSocket = new ServerSocket... // Create server socket serverSocket.setSoTimeout(1000); serverSocket.accept(); 

如果ServerSocket在1000毫秒内没有收到任何内容,则会抛出SocketTimeoutException 。 请注意,对于所有使用超时的套接字,不仅是ServerSocket ,都会抛出此exception。 这意味着抛出SocketTimeoutExceptionSocket对象在超时之前没有从被调用服务器返回任何内容。

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

如果在connect(),上指定超时connect(),或者如果在SocketServerSocket上调用setSoTimeout()并且read()accept()超时,则会得到SocketTimeoutException 。 在connect(),的情况下connect(),这是一个严重的问题:您尝试连接的任何一个不存在或位于防火墙后面,您无法分辨哪个。

如果对等方主动拒绝您的连接请求,您将获得connection refused连接,这通常意味着您指定的端口没有任何监听。 请注意,与超时不同,这意味着收到了响应,并且它是否定的。

 Caused by: java.net.SocketTimeoutException: connect timed out 

由于对等方不可用而无法连接时。 你的第二个疑问,读什么? 比你会得到的

  Caused by: java.net.SocketTimeoutException: Read timed out 

如果对等方处于活动状态但拒绝连接,则第三种可能性connection refused