简体   繁体   中英

Proper way to shutdown Apache httpcomponents blocking HTTP server

I have application with Apache HttpComponents 4.4.1 synchronous server , which runs several HTTP "services", for each of them I start HTTP server on different port. When the user decides to stop the service, I shut down HTTP server running on this port with this code:

org.apache.http.impl.bootstrap.HttpServer server;
....

public void stopServer(){
    server.shutdown(42, TimeUnit.MICROSECONDS);
}

I have the following problem on Linux: If there are Keep-alive connections opened (there is no request processing), these sockets are not closed. Only ServerSocket is closed:

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

In attempt to start again HTTP server on the same port a BindingException is thrown:

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)

On Windows the behavior is the same , however there is no BindingException and the server starts process requests without any problems.

Turns out to be a bug: https://issues.apache.org/jira/browse/HTTPCORE-420 oleg has already proposed a fix. I will update this when it is released officially.

Your problem is that connection is not closed. The HTTP specification does not specify how long a persistent connection should be kept alive.

From documentation :

Some HTTP servers use a non-standard Keep-Alive header to communicate to the client the period of time in seconds they intend to keep the connection alive on the server side. HttpClient makes use of this information if available. If the Keep-Alive header is not present in the response, HttpClient assumes the connection can be kept alive indefinitely.

So they advise to create your KeepAliveStrategy in order to terminate those connections after certain time:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM