什么可能导致套接字ConnectException:连接超时?

我们有一个Webstart客户端,它通过使用java.net.HttpsURLConnection通过HTTPS发送序列化对象来与服务器通信。

在我的本地机器和办公室的测试服务器上,一切都运行得很好,但我遇到了一个非常非常奇怪的问题,这个问题只发生在我们的生产和登台服务器上(偶尔也会发生)。 我知道这些服务器和我们办公室的服务器之间的主要区别在于它们位于其他地方并且客户端 – 服务器与它们的通信速度相当慢,但在此之前它在生产中也能正常工作。

无论如何,这是发生了什么:

  • 客户端在设置读取超时和HttpURLConnection上的Content-Type等属性之后调用其上的getOutputStream()以获取要写入的流。
  • 此时,据我所知,客户端会挂起一段时间。
  • 然后客户端抛出以下exception:
 java.net.ConnectException:连接超时:连接
     at java.net.PlainSocketImpl.socketConnect(Native Method)
    在java.net.PlainSocketImpl.doConnect(未知来源)
     at java.net.PlainSocketImpl.connectToAddress(Unknown Source)
    在java.net.PlainSocketImpl.connect(未知来源)
    在java.net.SocksSocketImpl.connect(未知来源)
    在java.net.Socket.connect(未知来源)
     at com.sun.net.ssl.internal.ssl.SSLSocketImpl.connect(Unknown Source)
    在com.sun.net.ssl.internal.ssl.BaseSSLSocketImpl.connect(未知来源)
    在sun.net.NetworkClient.doConnect(未知来源)
    在sun.net.www.http.HttpClient.openServer(未知来源)
    在sun.net.www.http.HttpClient.openServer(未知来源)
    在sun.net.www.protocol.https.HttpsClient。(未知来源)
    在sun.net.www.protocol.https.HttpsClient.New(未知来源)
     at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.getNewHttpClient(Unknown Source)
    在sun.net.www.protocol.http.HttpURLConnection.plainConnect(未知来源)
    在sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(未知来源)
     at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(Unknown Source)
     at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(Unknown Source)

请注意,这不是SocketTimeoutExceptionHttpURLConnection上的connect()方法表示如果在建立连接之前超时到期,它将抛出。 此外,当发生这种情况时,我能够调用conn.getResponseCode()并获得200的响应代码。

  • 在服务器端,在ObjectInputStream的构造函数中抛出EOFException ,该构造函数尝试读取序列化头但由于客户端永远不会获取要写入的OutputStream而失败。

如果它有帮助,这里是在调用getOutputStream()之前在HttpsURLConnection进行的调用(编辑后只显示正在进行的调用而不是代码的整个结构这样做):

 HttpsURLConnection conn = (HttpsURLConnection) url.openConnection(); conn.setUseCaches(false); conn.setReadTimeout(30000); conn.setRequestProperty("Cookie", cookie); conn.setDoOutput(true); conn.setRequestProperty("Content-Type", "application/x-java-serialized-object"); conn.getOutputStream(); 

问题是,我不知道如何发生这种情况,特别是考虑到它偶尔会发生(我没有明确的活动模式),即使这样,只有当客户端和客户端之间存在(相对)高延迟时服务器。

鉴于我迄今为止找到的关于java.net.ConnectException: Connect timed out ,我想知道我们的服务器运行在网络上是不是网络或防火墙问题…但是这不是鉴于请求显然已经通过servlet,对我来说很有意义。 此外,在同一网络上运行的其他应用程序尚未报告类似问题。

有谁知道这可能是什么原因,甚至我应该调查什么?

我们遇到过与您类似的情况。 通常在高负荷下并且在测试时不易重现。 还没有解决它,但这是我们经历的步骤。

如果是防火墙问题,我们会收到连接拒绝或SocketTimeoutexception。

1)您是否能够在服务器上的访问日志中跟踪这些请求 – 它们是否显示HTTP状态200或404或其他? 在我们的例子中,服务器(在本例中为IIS)日志显示客户端关闭了连接而不是服务器。 所以这是一个谜。

更新:如果客户端总是获得200,那么服务器实际上已经发回一些响应,但我怀疑响应字节大小(如果这是在访问日志中记录的) 将显示与正常响应大小不同的值那个要求。

如果它显示相同大小的响应,那么您有一个(可能不合理)条件,服务器实际上正确响应但客户端没有得到响应,因为连接在两者之间的某处终止。

2)网络管理团队查看TCP / IP流量以确定哪个终端(或中间路由器)正在终止HTTP / TCP-IP对话。 一旦我们了解哪一端终止,那么连接就是为什么。 知识渊博的人可以窥探

3)服务器上是否配置/限制了最大数量的请求 – 是否会限制您的连接?

4)是否有可以丢弃请求的中间负载平衡器?

更新:我们想要的另一件事,但没有完成的是在客户端和服务器之间创建静态路由以减少其间的跳数并确保没有与网络相关的连接丢失。 见http://en.wikipedia.org/wiki/Static_routing

5)另一个建议是设置ConnectTimeout以查看它们是否具有更高的值。 更新:您可能想尝试conn.getErrorStream()

如果连接失败但服务器仍发送有用数据,则返回错误流。 如果未连接连接,或者连接时服务器没有错误,或者服务器出现错误但未发送错误数据,则此方法将返回null。

6)还可以尝试在服务器上相隔5秒钟进行一组线程转储,以查看是否有任何线程在服务器上显示这些传入请求。

更新:截至今天,我们学会了解决这个问题,因为我们总计故障率为每天400,000个请求中的200-300,即0.00075%