CentOS 4上Java 1.6带来的相当神秘的SocketException

CentOS 4上Java 1.6带来的相当神秘的SocketException,java,networking,Java,Networking,我有一个JAX-RSWeb服务的JUnit测试。测试启动嵌入式tomcat,然后通过ApacheCXFJAX-RS客户机与之对话 考虑这个回溯: Caused by: java.net.SocketException: Socket Closed at java.net.PlainSocketImpl.getOption(PlainSocketImpl.java:286) at java.net.Socket.getSoTimeout(Socket.java:10

我有一个JAX-RSWeb服务的JUnit测试。测试启动嵌入式tomcat,然后通过ApacheCXFJAX-RS客户机与之对话

考虑这个回溯:

Caused by: java.net.SocketException: Socket Closed
        at java.net.PlainSocketImpl.getOption(PlainSocketImpl.java:286)
        at java.net.Socket.getSoTimeout(Socket.java:1032)
        at sun.net.www.http.HttpClient.available(HttpClient.java:356)
        at sun.net.www.http.HttpClient.New(HttpClient.java:273)
        at sun.net.www.http.HttpClient.New(HttpClient.java:310)
        at sun.net.www.protocol.http.HttpURLConnection.getNewHttpClient(HttpURLConnection.java:987)
        at sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:923)
        at sun.net.www.protocol.http.HttpURLConnection.connect(HttpURLConnection.java:841)
        at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:1031)
这仅在CentOS 4.8上失败。同样的单元测试(启动一个嵌入式tomcat,然后与其中的web服务进行对话)也可以在各种其他系统上正常工作。注意这个回溯的极端奇怪:
HttpHRLConnection
调用了
HttpClient
来获得一个新的连接,而后面的类显然在返回连接之前关闭了自己的套接字,我的任何代码都可以访问它

此外,测试中有朋友对相同的服务进行相同的服务器设置,并与之交谈,没有任何问题

更进一步,以下咒语(略为缩写)是一种变通方法:

@Before
public void pingServiceToWorkAroundCentos() {
   try {
      /* ... code to make a connection to the service and close it ... */
   } catch (Throwable t) {
      // do nothing
   }
}
换句话说,如果我在运行每个测试用例之前安排了一个额外的一次性连接,那么这个问题就解决了


这可能是什么?

因为这里只有回溯,没有代码,所以我假设存在某种竞争条件或错误,当当前线程试图获取输出流时,套接字在另一个线程之前被关闭

查看JDK的源代码,我看到这个

public Object getOption(int opt) throws SocketException {
    if (isClosedOrPending()) {
        throw new SocketException("Socket Closed");
    }
    ... snip ...
isClosedOrPending方法检查内部FD是否为null,或者关闭是否处于挂起状态,即是否已在套接字上调用了close


祝你好运找到它。

它没有什么神秘之处。您已关闭插座,然后继续使用它


关闭套接字的输入流或输出流会关闭另一个流和套接字。

我很确定这是一个JDK错误

HttpClient在最近的提交中被修改:


getSoTimeout()调用需要位于try/catch块中,不幸的是,目前唯一的实际选择是降级JDK

看起来类似于我们遇到的一个问题,httpclient池连接比tomcat中相应的服务器端连接保持活动时间更长。基本上,这会导致httpclient连接池中的连接过时。当httpclient尝试使用这些时,它们基本上失败了。我相信httpclient实际上是通过使用标准重试处理程序来恢复的


解决方案是仔细检查客户端和服务器端的超时设置以及重试策略。

您是否尝试过
strace-e network
ing it?+1使用“神秘”而不是“怪异”或“奇怪”一词。“神秘”更贴切,依我看。不,看看回溯。这发生在HttpURLConnection内部,我无法在创建和使用之间插入结束符。是的,我也读过。问题是,在HttpURLConnection打开它和尝试获取该选项之间,它是如何关闭的?需要查看所有代码。我假设它被其他线程关闭。“所有代码”都是ApacheCXF的。不太适合邮寄。在HttpURLConnection创建套接字和获取选项之间,Java线程如何访问套接字?它完全位于JDK中连接代码的私有字段中。