2016-07-13 6 views
-1

クライアントマシンからRESTサーバーに、Jerseyを使用して通信するために使用される(大幅に簡略化された)コードは次のとおりです。開始時に接続を確立するための5分のタイムアウトと、下位のソケットからの読み取りのための2分のタイムアウトがあります。クライアントで読み取りタイムアウト後にジャージーサーバーCLOSE_WAITがリークします

public class JerseyClient { 

    private final Map<Action, WebResource> resources; 

    public JerseyClient(URI uri) { 
    this.resources = new EnumMap<Action, WebResource>(Action.class); 
    this.resources.put(Action.Put, getClient().resource(Action.Put.getURI())); 
    this.resources.put(Action.Query, getClient().resource(Action.Query.getURI())); 
    } 

    private String submit(Action action, String input) throws Exception { 
    WebResource resource = this.resources.get(action); 
    ClientResponse response = null; 
    synchronized (resource) { 
     try { 
      response = resource.accept(MediaType.APPLICATION_JSON_TYPE, 
        MediaType.TEXT_PLAIN_TYPE).type(MediaType.APPLICATION_JSON_TYPE). 
        post(ClientResponse.class, input); 
      String responseString = null; 
      // Handle the response and produce a response string... 
     return responseString; 
     } finally { 
     if (response != null) { 
      response.close(); 
     } 
     } 
    } 
    } 

    private static Client getClient() { 
    Client client = Client.create(); 
    client.setReadTimeout(2*60*1000); 
    client.setConnectTimeout(5*60*1000); 
    return client; 
    } 

    private enum Action { 
    Put, Query; 
    public URI getURI(){ 
     switch (this) { 
     case Put: 
      return URI.create("PUT_URI"); 
     case Query: 
      return URI.create("QUERY_URI"); 
     default: 
      throw new InvalidStateException("Illegal action"); 
     } 
    } 
    } 
} 

クライアントで読み取りタイムアウトが発生しない限り、上記のコードは期待通りに機能します。この場合、SocketTimeoutExceptionがスローされ、上記のJerseyClientメソッドのsubmit()メソッドの応答オブジェクトはnullのままであるため、基底ソケットは決して完全に閉じられません。 、他方の側に、サーバはCLOSE_WAIT状態に入るため

は明らかに(すなわち、それはTCP仕様に従って、クライアントからFINパケットを受信した)クライアントによるソケットの部分的閉塞があります。しかし、ACKはクライアント(response.close()が呼び出された場合に送信される)から決して得られないので、(図のようにnetstat)の接続を維持するので、クライアントからのRESTコールのタイムアウトが発生するたびにCLOSE_WAITサーバー上で

上記のコードを完全に再エンジニアリングすることなく、問題を解決する方法はありますか?

答えて

1

あなたの説明は意味をなさない。状態の名前はCLOSED_WAITではなく、CLOSED_WAITであり、その正しい名前が表すものを意味します。ローカルのアプリケーションがピアからのリモートクローズを受信した後でソケットを閉じるのを待機しています。

サーバーはCLOSE_WAITに入っている場合:

  1. クライアントは、ソケットを閉じました。
  2. サーバーにはがありません。ソケットを閉じました。これはサーバーのバグです。
  3. サーバは、ソケットを閉じることによってFINを発行するまで、クライアントから最終的なACKを得ることはありません。 ACKは、FINの肯定応答である。サーバがFINを発行するまで、クライアントにはACKはありません。
  4. クライアントのACKではなく、CLOSE_WAITから取得するのはクローズです。
  5. クライアントでのresponse.close()の呼び出しは、クライアントが最終的なACKを送信することとは関係ありません。
+0

もちろん、CLOSE_WAITについては当然です。問題はハリーで書かれましたが、修正されました。シナリオは当初記載されたままである。ありがとうございました。 :-) – PNS

+0

シナリオは、サーバーがソケットをクローズしておらず、クライアントが持っていることです。これはもともと説明したものとまったく逆です。 – EJP

+0

私たちは、多くのCLOSE_WAIT接続が存在するという事実に基づいて、この問題を追跡しています。ドキュメンテーションに基づいて誰が何をしたかにかかわらず、 'response.close()'がクライアントで呼び出される必要があります。上記のコードでこれを行う方法はありますか?それが主な質問です。ありがとう。 – PNS

関連する問題