正确关闭Apache httpcomponents阻止HTTP服务器的方法

时间:2016-03-24 10:44:38

标签: java apache-httpcomponents

我有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,服务器启动进程请求没有任何问题。

2 个答案:

答案 0 :(得分:1)

原来是一个错误:https://issues.apache.org/jira/browse/HTTPCORE-420 oleg已经提出了修复方案。我会在正式发布后更新。

答案 1 :(得分:0)

您的问题是连接未关闭。 HTTP规范没有规定持久连接应该保持多长时间。

来自documentation

  

某些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();