2016-03-24 3 views
3

У меня есть приложение с Apache HttpComponents 4.4.1 синхронный сервер, который выполняет несколько HTTP-сервисов, для каждого из них я запускаю HTTP-сервер на другом порту. Когда пользователь решает остановить службу, я выключаю HTTP-сервер работает на этом порту с этим кодом:Правильный способ отключения Apache httpcomponents, блокирующий 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

Не могли бы вы собрать тестовый пример, воспроизводящий проблему, и поднять JIRA по адресу https://issues.apache.org/jira/? – oleg

ответ

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

Я использую http-components ** server **. Мой код работает на стороне сервера. Я не знаю, какие клиенты будут подключаться к моему серверу. –

Смежные вопросы