我有Apache HttpComponents 4.4.1 同步服务器的应用程序,它运行多个HTTP“服务”,每个我在不同的端口启动HTTP服务器。当用户决定停止服务时,我使用以下代码关闭在此端口上运行的HTTP服务器:
org.apache.http.impl.bootstrap.HttpServer server;
....
public void stopServer(){
server.shutdown(42, TimeUnit.MICROSECONDS);
}
我在Linux上遇到以下问题:如果打开了Keep-alive连接(没有请求处理),则不会关闭这些套接字。仅关闭ServerSocket:
netstat -aon | grep 58276
TCP 127.0.0.1:50658 127.0.0.1:58276 ESTABLISHED 18012
TCP 127.0.0.1:58276 127.0.0.1:50658 ESTABLISHED 18012
尝试在同一端口上重新启动HTTP服务器时抛出BindingException:
Caused by: java.net.BindException: Address already in use
at java.net.PlainSocketImpl.socketBind(Native Method)
at java.net.PlainSocketImpl.socketBind(PlainSocketImpl.java:521)
at java.net.PlainSocketImpl.bind(PlainSocketImpl.java:414)
at java.net.ServerSocket.bind(ServerSocket.java:326)
at java.net.ServerSocket.<init>(ServerSocket.java:192)
at javax.net.DefaultServerSocketFactory.createServerSocket(ServerSocketFactory.java:170)
at org.apache.http.impl.bootstrap.HttpServer.start(HttpServer.java:116)
在Windows上,行为是相同的,但没有BindingException,服务器启动进程请求没有任何问题。
答案 0 :(得分:1)
原来是一个错误:https://issues.apache.org/jira/browse/HTTPCORE-420 oleg已经提出了修复方案。我会在正式发布后更新。
答案 1 :(得分:0)
您的问题是连接未关闭。 HTTP规范没有规定持久连接应该保持多长时间。
某些HTTP服务器使用非标准
Keep-Alive
标头 与客户沟通他们打算以秒为单位的时间段 保持服务器端的连接活动。HttpClient
使用 这些信息(如果有的话)。如果Keep-Alive
标题不是 在响应中,HttpClient
假设连接可以 无限期地保持活着。
因此,他们建议您创建KeepAliveStrategy
以便在一定时间后终止这些连接:
ConnectionKeepAliveStrategy myStrategy = new ConnectionKeepAliveStrategy() {
public long getKeepAliveDuration(HttpResponse response, HttpContext context) {
// Honor 'keep-alive' header
HeaderElementIterator it = new BasicHeaderElementIterator(
response.headerIterator(HTTP.CONN_KEEP_ALIVE));
while (it.hasNext()) {
HeaderElement he = it.nextElement();
String param = he.getName();
String value = he.getValue();
if (value != null && param.equalsIgnoreCase("timeout")) {
try {
return Long.parseLong(value) * 1000;
} catch(NumberFormatException ignore) {
}
}
}
HttpHost target = (HttpHost) context.getAttribute(
HttpClientContext.HTTP_TARGET_HOST);
if ("www.naughty-server.com".equalsIgnoreCase(target.getHostName())) {
// Keep alive for 5 seconds only
return 5 * 1000;
} else {
// otherwise keep alive for 30 seconds
return 30 * 1000;
}
}
};
CloseableHttpClient client = HttpClients.custom()
.setKeepAliveStrategy(myStrategy)
.build();