2014-07-06 19 views
6

uruchamiając netstat na serwerze:
dopóki kilka dni temu: Widziałam połączenie będąc ESTABLISHED tylko przez około sekundę, a potem zniknąć z listy
TERAZ: pozostaje jako ESTABLISHED przez około 10 sekund, a następnie przechodzi do FIN_WAIT1 i FIN_WAIT2Android: HttpURLConnection nie rozłącza

kod Android jest taka sama, serwer jest wciąż ten sam

Czy to możliwe, że niektóre aktualizacje Androida mogły coś zmienić?

Naprawdę nie mogę tego wyjaśnić.

Zgłaszam poniższy kod. urlConnection.disconnect() zostaje wykonany, ale połączenie pozostaje ustanowione na serwerze.

HttpURLConnection urlConnection = null; 
    System.setProperty("http.keepAlive", "false"); 

    try { 
     URL url = new URL(stringUrl); 
     urlConnection = (HttpURLConnection) url.openConnection(); 
     InputStream instream = new BufferedInputStream(urlConnection.getInputStream()); 
     ... 
     instream.close(); 
    } catch (MalformedURLException e) { 
     e.printStackTrace(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } finally { 
     if (urlConnection!=null) { 
      urlConnection.disconnect(); 
     } 
    } 
+0

Spróbuj ustawić 'Connection' nagłówek' close'. – hgoebl

+0

Próbowałem, i zamiast FIN_WAIT1 i FIN_WAIT2, przechodzi w TIME_WAIT –

Odpowiedz

1

Jak na jak działa protokół TCP, po zamknięciu połączenia, to nie automatycznie zniknie z poziomu listy gniazda.

Kiedy jesteś wysłać sygnał zakończenia do drugiej części, tam zaczyna się protokół (procedura, bardziej podobne), gdzie pierwszym krokiem jest właśnie zamiar zamknięcia połączenia. Wysyłasz sygnał do drugiego węzła i dotyczy to stanu FIN_WAIT1.

Gdy użytkownik odbierze ten sygnał, następnym krokiem jest potwierdzenie go od strony zdalnej. Oznacza to, że serwer przeciwległy wysyła inny sygnał symbolizujący, że węzeł jest gotowy do zamknięcia połączenia. To byłby status FIN_WAIT2.

Pomiędzy tymi dwoma krokami może się zdarzyć, że zdalny węzeł nie odpowie jeszcze (więc nie zostanie potwierdzone, że chcesz zamknąć połączenie). W tym czasie będziesz w stanie pośrednim o nazwie CLOSE_WAIT (wznawianie: po wysłaniu sygnału FIN do zdalnego serwera i nie odpowiedzieli jeszcze).

Stan TIME_WAIT oznaczałby, że dajesz wdzięczny czas serwerowi przed ostatecznym zamknięciem go w celu otrzymania niektórych pakietów. Robisz to, ponieważ mogą wystąpić anomalie połączeń, a serwer zdalny mógł nie otrzymać komunikatu "odłączenie" i wysłać ci pakiet. Gdy tak się stanie, zamiast tworzyć nowe gniazdo między obydwoma węzłami, kojarzysz je ze stanem, który masz w stanie TIME_WAIT i po prostu odrzucasz ten pakiet, ponieważ prawdopodobnie numer porządkowy nie zostanie zamówiony.

Istnieje kilka innych stanów: you might see, ale zgodnie ze sposobem, w jaki je opisujesz, wydaje mi się to całkiem normalne, chyba że podczas wywoływania metody .disconnect() będzie obowiązywał stan . W takim przypadku coś nie działa zgodnie z oczekiwaniami (może być związane z jakimś przeciążeniem lub niezoptymalizowanym kodem, co może spowodować, że wykonanie będzie bardzo powolne).

1

Gdy wszystkie dane dotyczące strumienia wejściowego zostaną zużyte, połączenie zostanie automatycznie zwolnione i dodane do puli połączeń. Podstawowe połączenie z gniazdem nie zostanie zwolnione, zakładając, że połączenie zostanie ponownie użyte w niedalekiej przyszłości. Dobrą praktyką jest wywoływanie bloku disconnect w bloku finally, ponieważ zajmuje się uwolnieniem połączenia w przypadku exceptions.

Tutaj jest wdrożenie metody odczytu FixedLengthInputStream:

@Override public int read(byte[] buffer, int offset, int count) throws IOException { 
     Arrays.checkOffsetAndCount(buffer.length, offset, count); 
     checkNotClosed(); 
     if (bytesRemaining == 0) { 
      return -1; 
     } 
     int read = in.read(buffer, offset, Math.min(count, bytesRemaining)); 
     if (read == -1) { 
      unexpectedEndOfInput(); // the server didn't supply the promised content length 
      throw new IOException("unexpected end of stream"); 
     } 
     bytesRemaining -= read; 
     cacheWrite(buffer, offset, read); 
     if (bytesRemaining == 0) { 
      endOfInput(true); 
     } 
     return read; 
    } 

Kiedy zmienna bytesRemaining staje 0, endOfInput nazywa który będzie dodatkowych wojsk metody zwalniania połączenia z prawdziwego parametrem, który zapewnia połączenie jest połączono. To jest implementacja metody release. Ostatnie sprawdzenie, czy połączenie ma zostać zamknięte lub dodane do puli połączeń w celu ponownego użycia.

public final void release(boolean reusable) { 
    // If the response body comes from the cache, close it. 
    if (responseBodyIn == cachedResponseBody) { 
     IoUtils.closeQuietly(responseBodyIn); 
    } 
    if (!connectionReleased && connection != null) { 
     connectionReleased = true; 
     // We cannot reuse sockets that have incomplete output. 
     if (requestBodyOut != null && !requestBodyOut.closed) { 
      reusable = false; 
     } 
     // If the headers specify that the connection shouldn't be reused, don't reuse it. 
     if (hasConnectionCloseHeader()) { 
      reusable = false; 
     } 
     if (responseBodyIn instanceof UnknownLengthHttpInputStream) { 
      reusable = false; 
     } 
     if (reusable && responseBodyIn != null) { 
      // We must discard the response body before the connection can be reused. 
      try { 
       Streams.skipAll(responseBodyIn); 
      } catch (IOException e) { 
       reusable = false; 
      } 
     } 
     if (!reusable) { 
      connection.closeSocketAndStreams(); 
      connection = null; 
     } else if (automaticallyReleaseConnectionToPool) { 
      HttpConnectionPool.INSTANCE.recycle(connection); 
      connection = null; 
     } 
    } 
} 

Uwaga: Wcześniej odpowiedziało na kilka pytań związanych z SO HttpURLConnection, które mogą pomóc w zrozumieniu podstawowej implementacji. Oto linki: Link1 i Link2.

+0

* Czy * w końcu {} uzyskać wywołanie w przypadku wyjątku? –

+0

@ jesses.co.tt Tak ostatecznie blok jest wykonywany w przypadku wyjątku. –

+0

fajny thx ... nie był pewien, ale dobrze wiedzieć. –

0

Trzeba odłączyć otwartych URLConnection

HttpURLConnection urlConnection = null; 
System.setProperty("http.keepAlive", "false"); 

try { 
    URL url = new URL(stringUrl); 
    urlConnection = (HttpURLConnection) url.openConnection(); 
    InputStream instream = new BufferedInputStream(urlConnection.getInputStream()); 
    ... 
    instream.close(); 
    urlConnection.disconnect(); //HERE 
} catch (MalformedURLException e) { 
    e.printStackTrace(); 
} catch (IOException e) { 
    e.printStackTrace(); 
} finally { 
    if (urlConnection!=null) { 
     urlConnection.disconnect(); 
    } 
} 
+0

Końcowy blok jest wykonywany w przypadku scenariuszy normalnych i wyjątków. Dlatego nie ma potrzeby wywoływania 'disconnect' w bloku try. –

Powiązane problemy