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

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 に答える
0

それについて神秘的なことは何もありません。ソケットを閉じてから、引き続き使用しました。

ソケットの入力ストリームまたは出力ストリームのいずれかを閉じると、もう一方のストリームとソケットが閉じられます。

于 2013-01-11T07:10:16.510 に答える