2

我对 JAX-RS Web 服务进行了 JUnit 测试。测试启动嵌入式 tomcat,然后通过 Apache CXF JAX-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
   }
}

换句话说,如果我在运行每个测试用例之前安排一个额外的一次性连接,那么无论这个问题是什么,都会用完。

这可能是什么?

4

4 回答 4

1

由于这里只有一个回溯并且没有代码,我假设存在某种竞争条件或错误,即当前线程试图获取 OutputStream 时,另一个线程先关闭了套接字。

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

public Object getOption(int opt) throws SocketException {
    if (isClosedOrPending()) {
        throw new SocketException("Socket Closed");
    }
    ... snip ...

isClosedOrPending 方法检查内部 FD 是否为 null 或关闭是否挂起,即在套接字上调用了关闭。

祝你好运追踪它。

于 2013-01-11T03:15:03.310 回答
0

没什么神秘的。您已关闭套接字,然后继续使用它。

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

于 2013-01-11T07:10:16.510 回答
0

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

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

于 2013-01-29T09:53:13.457 回答
0

我很确定这是一个 JDK 错误。

HttpClient 在最近的提交中进行了修改:

http://hg.openjdk.java.net/jdk7u/jdk7u/jdk/diff/e6dc1d9bc70b/src/share/classes/sun/net/www/http/HttpClient.java

getSoTimeout() 调用需要在 try/catch 块中,不幸的是,目前唯一真正的选择是降级 JDK。

于 2013-01-29T09:26:49.187 回答