2013-12-19 4 views
0

Я подключаюсь к веб-службе через Java-приложение и реализацию HttpsURLConnection. Я открываю соединение, используйте try с блоком ресурсов, чтобы открыть (и закрыть, когда закончите) входной поток и считыватель потока ввода, а затем вызвать connection.disconnect в блоке finally. Код ниже, и он работает большую часть времени.HttpsURLConnection - прерывистое соединение Ошибочные ошибки

HttpsURLConnection connection = null; 
    try{  
     // basic authentication 
     String encodedAuthString = 
      DatatypeConverter.printBase64Binary((userName + ":" + password) 
       .getBytes()); 

     connection = (HttpsURLConnection) url.openConnection(); 
     connection.setRequestMethod("GET"); 
     connection.setRequestProperty("Authorization", "Basic " + encodedAuthString); 

     //try-with-resource to close connections when complete 
     try(InputStream in = connection.getInputStream(); 
      InputStreamReader isr = new InputStreamReader(in)){ 
      int numCharsRead; 
      char[] charArray = new char[1024]; 
      StringBuffer sb = new StringBuffer(); 
      while ((numCharsRead = isr.read(charArray)) > 0) { 
       sb.append(charArray, 0, numCharsRead); 
      } 

      jsonResult = sb.toString(); 
     } 

    } 
    catch (Exception e){ 
     throw e; 
    } finally { 
     if(connection!= null) 
      connection.disconnect(); 
    } 

Тем не менее, этот код можно было бы назвать несколько раз в одну секунду с помощью нескольких потоков (хотя фактический метод, содержащий синхронизирован, так что только один поток может получить доступ к соединению в то время). При работе с нашими сетевыми ребятами мы обнаружили, что даже если приложение вызывает «connection.disconnect()», соединение не отключается сразу на сервере. Мы видим, что вызов отключается в журналах сервера, но приложение Java пытается подключиться снова, прежде чем сервер полностью отключится, что приведет к ошибке «Ошибка соединения».

Должно ли все-таки принудительно полностью отключиться через java, прежде чем подключаться снова или через настройку сервера при вызове разъединения? Или способ сделать это быстрее, чтобы уменьшить вероятность ошибок? Я мог бы повторить соединение до тех пор, пока он не будет успешно подключен, но это похоже на взлома.

Может ли кто-нибудь помочь указать мне в правильном направлении?

Update - 01/06/2013 - Как я продолжил расследование, я обнаружил, прочитав ТСРйитр, что мой клиент подключается на тот же порт для 100 запросов, то на 101-м запроса, изменения порта и Я получаю ошибку. В конечном итоге соединение восстановится и начнет отправлять и получать запросы на новый порт, но для восстановления может потребоваться до минуты. Я включил tcpdump ниже. Вы можете видеть, что, когда клиент отправляет новый порт, IP-адрес назначения возвращает «R» eset на новый порт. Из-за этого я думаю, что ошибка является результатом ошибки в месте назначения, а не от моего клиента, но я все еще пытаюсь проверить, так как мое понимание на этом уровне ограничено.

13:20:25.925760 IP DESTINATION_IP.https > CLIENT_IP.53321: P 197809:197846... 
13:20:25.925819 IP CLIENT_IP.53321 > DESTINATION_IP.https: . ack 197846 wi... 
13:20:25.926393 IP CLIENT_IP.53321 > DESTINATION_IP.https: P 82874:82911(3... 
13:20:25.926424 IP CLIENT_IP.53321 > DESTINATION_IP.https: F 82911:82911(0... 
13:20:25.928629 IP CLIENT_IP.53322 > DESTINATION_IP.https: S 702514925:702... 
13:20:26.005902 IP DESTINATION_IP.https > CLIENT_IP.53321: . ack 82911 win... 
13:20:26.008461 IP DESTINATION_IP.https > CLIENT_IP.53322: R 0:0(0) ack 70... 
13:20:26.011274 IP DESTINATION_IP.https > CLIENT_IP.53321: P 197846:197883... 
13:20:26.011290 IP CLIENT_IP.53321 > DESTINATION_IP.https: R 494623963:494... 
13:20:26.011300 IP DESTINATION_IP.https > CLIENT_IP.53321: F 197883:197883... 
13:20:26.011305 IP CLIENT_IP.53321 > DESTINATION_IP.https: R 494623963:494... 

ответ

-1

Соединение поддерживается в сети из-за HTTP Keep Alive.

Это может быть грубо отключено сервером, что делает невозможным, чтобы клиентская библиотека HTTP определяла, когда она завершила отправку данных, то есть не отправляет заголовок Content-Length, а также не использует закодированную кодировку. Однако многие веб-фреймворки делают то или другое автоматически, и приложение может полагаться на них в любом случае, поскольку клиентское приложение все еще должно определить, когда сервер завершил передачу данных, и он может полагаться на что-то вроде Content-Length или chunked encoding чтобы определить это!

Однако отказ от отказа в подключении вряд ли будет связан с этим явлением - на самом деле HTTP Keepalive должен сделать это less Вероятно, вы увидите сообщение об ошибке отказа, а не больше, поскольку оно повторно использует существующие соединения.

+0

№. Невозможно сохранить соединение от разъединения(). Это проблема. Включение keepalive - это решение, а не проблема. – EJP

0

Избавьтесь от вызова disconnect(). Это предотвращает работу HTTP keepalive. Таким образом, вы используете гораздо больше TCP-соединений, которые заполняют очередь на сервере, что вызывает отказ в подключении (на некоторых платформах). Закрытие входного потока является достаточным в большинстве случаев.

+0

Спасибо за ответ. Я удалил разъединение, и это не изменило ситуацию. Однако я узнал больше информации, прочитав tcpdump и обновив свой оригинальный вопрос с дополнительной информацией. – jlteksolutions