以下是用于使用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
。
有没有办法解决这个问题,而没有完全重新设计上面的代码?
答案 0 :(得分:1)
您的描述没有意义。状态的名称是CLOSE_WAIT,而不是CLOSED_WAIT,它表示其(正确)名称表示的内容:它正在等待本地应用程序在从对等方接收到远程关闭后关闭套接字。
如果您的服务器正在输入CLOSE_WAIT:
response.close()
与发送最终ACK的客户端无关。