Java Jersey服务器关闭\u客户端读取超时后等待泄漏
以下是使用Java Jersey服务器关闭\u客户端读取超时后等待泄漏,java,rest,tcp,jersey,socket-timeout-exception,Java,Rest,Tcp,Jersey,Socket Timeout Exception,以下是使用Jersey从客户机通信到REST服务器的(大大简化的)代码。在开始时建立连接有5分钟的超时,从底层套接字读取有2分钟的超时 public class JerseyClient { private final Map<Action, WebResource> resources; public JerseyClient(URI uri) { this.resources = new EnumMap<Action, WebResource>(A
Jersey
从客户机通信到REST
服务器的(大大简化的)代码。在开始时建立连接有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");
}
}
}
}
公共类Jersey客户端{
私人最终地图资源;
公共运动衫客户端(URI){
this.resources=newenummap(Action.class);
this.resources.put(Action.put,getClient().resource(Action.put.getURI());
this.resources.put(Action.Query,getClient().resource(Action.Query.getURI());
}
私有字符串提交(操作、字符串输入)引发异常{
WebResource=this.resources.get(操作);
ClientResponse-response=null;
已同步(资源){
试一试{
response=resource.accept(MediaType.APPLICATION\u JSON\u类型,
MediaType.TEXT\u PLAIN\u TYPE).TYPE(MediaType.APPLICATION\u JSON\u TYPE)。
post(ClientResponse.class,输入);
字符串responseString=null;
//处理响应并生成响应字符串。。。
回报率;
}最后{
if(响应!=null){
response.close();
}
}
}
}
私有静态客户端getClient(){
Client=Client.create();
客户端.setReadTimeout(2*60*1000);
client.setConnectTimeout(5*60*1000);
返回客户;
}
私有枚举操作{
放置、查询;
公共URI getURI(){
开关(本){
案件付诸表决:
返回URI.create(“PUT_URI”);
个案查询:
返回URI.create(“查询URI”);
违约:
抛出新的InvalidStateException(“非法操作”);
}
}
}
}
除非在客户端触发读取超时,否则上述代码将按预期工作。在这种情况下,会抛出一个SocketTimeoutException
,因此上面JerseyClient
类的submit()
方法中的响应对象保持null
,因此底层套接字永远不会完全关闭
显然,客户端部分关闭了套接字,因为在另一端,服务器进入CLOSE\u WAIT
状态(即,根据TCP
规范,它已从客户端接收到FIN
数据包)。但是,由于它从未从客户端获得最终的ACK
(如果调用了response.close()
,则应发送该确认),因此它将连接保持在close\u WAIT
(如netstat
所示),因此,来自客户端的每个超时的REST
调用都可能在服务器上创建一个悬空的CLOSE\u WAIT
在不完全重新设计上述代码的情况下,有没有办法解决这个问题?您的描述毫无意义。状态的名称是CLOSE\u WAIT,而不是CLOSED\u WAIT,它的意思是它(正确的)名称所表达的:它在接收到来自对等方的远程关闭后,正在等待本地应用程序关闭套接字 如果您的服务器正在进入关闭\u等待:
response.close()
,与客户端发送最终ACK无关你的描述毫无意义。状态的名称是CLOSE\u WAIT,而不是CLOSED\u WAIT,它的意思是它(正确的)名称所表达的:它在接收到来自对等方的远程关闭后,正在等待本地应用程序关闭套接字 如果您的服务器正在进入关闭\u等待:
response.close()
,与客户端发送最终ACK无关你当然是对的,等等。这个问题写在一本哈利字典里,现在已经更正了。场景仍如最初所述。谢谢和+1.:-)这种情况下,服务器没有关闭套接字,而客户端关闭了套接字,这与最初描述的完全相反,尽管您进行了一些小的编辑,但现在仍然在描述。我们正在根据一个事实跟踪问题,即存在多个CLOSE_WAIT连接。无论谁做了什么,根据文档,都需要在客户端调用
response.close()
。在上面的代码中,有没有办法做到这一点?这是主要问题。谢谢。这是个新问题,我不明白。上述代码中没有可访问的套接字。它由基础库根据需要创建和关闭。它为POST打开,在收到响应或错误后关闭。因此,在代码中没有明显的地方,您可能希望提前或之后关闭套接字,或者不管您未声明的需求是什么。你应该考虑赞成或接受帮助你的答案。我建议你重新开始一个新的问题,新的证据,新的一切。这个问题是徒劳的。你说的“等一下”当然是对的。这个问题写在一本哈利字典里,现在已经更正了。场景仍如最初所述。谢谢和+1.:-)情况是服务器尚未关闭