2017-01-05 10 views
0

Мы подключаемся к поставщику данных и продолжаем читать данные XML в бесконечном цикле с использованием HttpClient. Мы уже установили тайм-аут соединения и тайм-аут сокета в коде Java. Однако, когда соединение закрыто на стороне HTTP-сервера, наше приложение не вызывает никаких исключений и просто висит там, ничего не делая. Из-за этого поведения, когда сервер работает, код Java не будет повторно подключаться. Есть ли способ узнать, было ли соединение сокета уже закрыто на стороне сервера?httpClient: как проверить, было ли соединение уже закрыто на стороне сервера.

Кроме того, https://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html упомянул, как закрыть связи STALE, но он по-прежнему не решает нашей проблемы.

Большое вам спасибо!

Фрагмент кода:

private static final HttpClientConnectionManager CONN_MGR = new BasicHttpClientConnectionManager(); 

public boolean connectToServer() { 
    disconnect(); 

    CredentialsProvider provider = new BasicCredentialsProvider(); 
    UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(username, password); 
    provider.setCredentials(AuthScope.ANY, credentials); 

    RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(15 * 1000) 
      .setSocketTimeout(15 * 1000).build(); 

    HttpClient client = HttpClientBuilder.create().setDefaultCredentialsProvider(provider) 
      .setSSLSocketFactory(sslsf) 
      .setConnectionManager(CONN_MGR) 
      .setDefaultRequestConfig(requestConfig).build(); 

    HttpGet request = new HttpGet(url); 

    try { 
     HttpResponse response = client.execute(request); 
     in = response.getEntity().getContent(); 
     reader = new BufferedReader(new InputStreamReader(in)); 
     connected = true; 

     return true; 
    } catch (Exception re) { 
     LOGGER.error("error", re); 
    } 

    return false; 
} 

public void process() { 
    String xml = null; 
    while (!shuttingDown) { 
     try { 

      /* if we know the server side closed the connection already here 
       we can simply return and scheduler will take care of anything else. */ 

      xml = reader.readLine(); 
      lastSeen = System.currentTimeMillis(); 
      if (StringUtils.isBlank(xml)) { 
       continue; 
      } 
      xml = xml.trim(); 

      // processing XML here 
     } catch (IOException | NullPointerException ie) { 
      /* We see SocketTimeoutException relatively often and 
      * sometimes NullPointerException in reader.readLine(). */ 
      if (!shuttingDown) { 
       if(!connectToServer()) { 
        break; 
       } 
      } 
     } catch (RuntimeException re) { 
      LOGGER.error("other RuntimeException", re); 
      break; 
     } 
    } 

    // the scheduler will start another processing. 
    disconnect(); 
} 

// called by the scheduler periodically 
public boolean isConnected() { 
    CONN_MGR.closeExpiredConnections(); 
    CONN_MGR.closeIdleConnections(15, TimeUnit.SECONDS); 
    long now = System.currentTimeMillis(); 
    if (now - lastSeen > 15000L) { 
     LOGGER.info("call disconnect() from isConnected()."); 
     disconnect(); 
    } 

    return connected; 
} 
+0

Возможно, поймав * IOException *? –

+0

В методе process() при обнаружении исключения IOException или NullPointerException мы отсоединяем и снова соединяем. –

+0

Я создал простой HTTP-сервер и использовал тот же код, что и код, чтобы узнать, помогает или нет CONN_MGR.closeExpiredConnections(). Через несколько минут я отключил HTTP-сервер, мой код все еще зависает в xml = reader.readLine() без каких-либо ошибок или исключений. Обратите внимание, что каждый раз, когда вызывается CONN_MGR.closeExpiredConnections(), я печатаю сообщение в файле журнала, и я действительно видел там сообщения. Одним словом, CONN_MGR.closeExpiredConnections() вызывается периодически в моем коде, но в итоге это не исключение, поэтому мой код не будет повторно подключаться. –

ответ

0

Я думаю, что с введением управления автоматическими ресурсов в Java 1.7

https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html

очистка устаревших соединений был позаботился и даже в худшем случае он тщательно следил за поставщиками внедрения, контролируя подключение

Ap ache HttpClient использует HttpClientConnectionManager и другие служебные классы, которые выполняют работу по очистке устаревших соединений.

+0

Большое спасибо, Барат! Первоначально я сказал, что закрытие устаревших связей не помогает. Скорее всего, я ошибаюсь, потому что обычно процесс() не возвращается и вызывается планировщиком Spring. По этой причине CONN_MGR.closeExpiredConnections() не вызывается периодически. Я дам вам знать, помогает или нет CONN_MGR.closeExpiredConnections(). –

+0

Привет @Barath! CONN_MGR.closeExpiredConnections() не помогает в моем случае. Для получения дополнительной информации см. Комментарий в моем сообщении. –

0

После последнего блока catch добавьте блок finally для вашего кода очистки.

finally { CONN_MGR.shutdown(); }

Согласно документации он закрывает диспетчер соединений и высвобождают ресурсы, выделенные

+0

Спасибо за ваш ответ, Ашиш! –

+0

Добро пожаловать. Дайте мне знать, если у вас есть другие проблемы –

0

Мы избежали проблем, закрывая соединение из другого потока, когда никаких данных не приходя в течение более 15 секунд. Более конкретно в настоящее время метода IsConnected() выглядит следующим образом:

// called by the scheduler periodically 
public boolean isConnected() { 
    long now = System.currentTimeMillis(); 
    if (now - lastSeen > 15000L) { 
     disconnect(); 
    } 

    return connected; 
} 

Конечно, чтение часть прибудет будет java.net.SocketException: Socket закрыто или java.lang.IllegalStateException: Подключение по-прежнему выделяется когда Бывает.

После этого изменения все работает нормально.