客户端

时间:2016-07-13 22:34:26

标签: java rest tcp jersey socket-timeout-exception

以下是用于使用REST从客户端计算机与Jersey服务器进行通信的(大大简化)代码。在开始时建立连接有5分钟超时,从底层套接字读取有2分钟超时。

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,因此上面submit()类的JerseyClient方法中的响应对象仍为null,因此底层套接字永远不会完全关闭。

显然,客户端部分关闭套接字,因为另一方面,服务器进入CLOSE_WAIT状态(即,它已从客户端收到FIN个数据包,如根据{{​​1}}规范)。但是,由于它永远不会从客户端获得最终TCP(如果调用了ACK则应该发送),它会将连接保持在response.close()(如CLOSE_WAIT所示),所以每次从客户端调出netstat可能会在服务器上创建一个悬空REST

有没有办法解决这个问题,而没有完全重新设计上面的代码?

1 个答案:

答案 0 :(得分:1)

您的描述没有意义。状态的名称是CLOSE_WAIT,而不是CLOSED_WAIT,它表示其(正确)名称表示的内容:它正在等待本地应用程序在从对等方接收到远程关闭后关闭套接字。

如果您的服务器正在输入CLOSE_WAIT:

  1. 客户端关闭套接字。
  2. 服务器关闭套接字。这是服务器中的错误。
  3. 在通过关闭套接字发出FIN之前,服务器永远不会从客户端获得最终的ACK。 ACK是对FIN的确认。在服务器发出FIN之前,客户端无需确认。
  4. 关闭是从CLOSE_WAIT,而不是客户端ACK。
  5. 在客户端调用response.close()与发送最终ACK的客户端无关。