HttpClient 之 CLOSE_WAIT
Using HttpClient Properly to Avoid CLOSE_WAIT TCP Connections
Apache HttpClient
is usually used like this in basic mode:
HttpClient httpClient = new HttpClient();
HttpMethod method = new GetMethod(uri);
try {
int statusCode = httpClient.executeMethod(method);
byte[] responseBody = method.getResponseBody();
// ...
return stuff;
} finally {
method.releaseConnection();
}
But this is not enough.
The issue is this: releasing the connection makes it available again to the HttpClient
instance, but does not close it, because HTTP 1.1 is used and it can pipeline further requests to the same host:port in the same connection.
Even though the server may have decided to close its end of the connection, the connection is still open on our client side and it will stay that way until an attempt to read from it is made (at which point the client will detect that the other end is closed). TCP works like that, there is the notion of a half-closed connection because close()
actually just means I will not send any more data, but you can still receive data from a connection that you closed but that has not yet been closed on the other end.
What happens next is that when the HttpClient
instance goes out of scope, it becomes available to the GC, but it will not be garbage collected immediately. Until the GC collects it, the socket connection held internally will stay open and the socket will be stuck in the CLOSE_WAIT state.
To fix this, the simplest way is to add: method.setRequestHeader("Connection", "close");
before executing the method. This will instruct HttpClient
to close the connection by itself once the full response has been received.
Another way is to do it in the finally
block:
httpClient.getHttpConnectionManager().closeIdleConnections(0);
An even better way is to not use a new HttpClient
object each time, but to reuse one that has been initialized with a MultiThreadedHttpConnectionManager
sized appropriately.
Of course in this case the connection manager must be shut down properly when the application shuts down:
private MultiThreadedHttpConnectionManager connectionManager;
private HttpClient httpClient;
public void init() {
connectionManager = new MultiThreadedHttpConnectionManager()
// ... configure connectionManager ...
httpClient = new HttpClient(connectionManager);
}
public void shutdown() {
connectionManager.shutdown();
}
public String process(String uri) {
HttpMethod method = new GetMethod(uri);
try {
int statusCode = httpClient.executeMethod(method);
byte[] responseBody = method.getResponseBody();
// ...
return stuff;
} finally {
method.releaseConnection();
}
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· 面试官:你是如何进行SQL调优的?
2018-01-03 Kubernetes之Controllers三
2018-01-03 优秀的程序猿
2018-01-03 如何写一个好的接口
2018-01-03 如何学习一门新技术
2018-01-03 Docker与.Net项目类型