java.net.SocketException: Reset połączenia

128

Otrzymuję następujący błąd podczas próby odczytu z gniazda. Robię readInt()się na to InputStream, a ja otrzymuję ten błąd. Po przeczytaniu dokumentacji sugeruje to, że część połączenia będąca klientem zamknęła połączenie. W tym scenariuszu jestem serwerem.

Mam dostęp do plików dziennika klienta i to nie zamyka połączenia, aw rzeczywistości jego pliki dziennika sugerują, że zamykam połączenie. Czy ktoś ma pojęcie, dlaczego tak się dzieje? Co jeszcze sprawdzić? Czy dzieje się tak, gdy istnieją lokalne zasoby, które być może osiągają progi?


Zwracam uwagę, że mam następujący wiersz:

socket.setSoTimeout(10000);

tuż przed readInt(). Jest ku temu powód (długa historia), ale po prostu ciekawy, czy są okoliczności, w których może to doprowadzić do wskazanego błędu? Mam serwer działający w moim IDE i zdarzyło mi się zostawić moje IDE w punkcie przerwania, a następnie zauważyłem, że dokładnie te same błędy zaczęły pojawiać się w moich własnych dziennikach w moim IDE.

W każdym razie, tylko o tym wspominając, mam nadzieję, że nie jest to czerwony śledź. :-(

niebieskawy
źródło
Czy masz ślady stosu z obu stron? Czy możesz dokładniej opisać architekturę sieci? (Przez szalony Internet? Na tej samej maszynie? Gdzieś pomiędzy?) Czy to się dzieje cały czas? Lub sporadycznie?
Stu Thompson,

Odpowiedzi:

116

Istnieje kilka możliwych przyczyn.

  1. Drugi koniec celowo zresetował połączenie, w sposób, którego nie będę tutaj dokumentować. Jest to rzadkie i generalnie niepoprawne, gdy oprogramowanie to robi, ale nie jest to nieznane w przypadku oprogramowania komercyjnego.

  2. Częściej jest to spowodowane zapisem do połączenia, którego drugi koniec został już normalnie zamknięty. Innymi słowy, błąd protokołu aplikacji.

  3. Może to być również spowodowane zamknięciem gniazda, gdy w buforze odbiorczym gniazda znajdują się nieprzeczytane dane.

  4. W systemie Windows „przerwanie połączenia przez oprogramowanie”, co nie jest tym samym, co „resetowanie połączenia”, jest spowodowane problemami z przesyłaniem danych z sieci. Jest na ten temat artykuł w bazie wiedzy Microsoft.

Markiz Lorne
źródło
@MattLyons Thanks. Istnieją znacznie lepsze artykuły MSDN niż to. Szczerze mówiąc, trudno mi w to uwierzyć. Połączenie nie będzie nawet istniało, dopóki nie zostaną ustanowione prawidłowe źródłowe i docelowe adresy IP. Artykuły MSDN, które widziałem, odnoszą się do trwałych błędów sieciowych przekraczających limit czasu połączenia.
Markiz Lorne
48

Reset połączenia oznacza po prostu, że odebrano TCP RST. Dzieje się tak, gdy Twój partner otrzymuje dane, których nie może przetworzyć, a może to mieć różne przyczyny.

Najprościej jest zamknąć gniazdo, a następnie zapisać więcej danych w strumieniu wyjściowym. Zamykając gniazdo, powiedziałeś swojemu rówieśnikowi, że skończyłeś mówić i może zapomnieć o Twoim połączeniu. Kiedy i tak wysyłasz więcej danych w tym strumieniu, peer odrzuca je z RST, aby poinformować Cię, że nie nasłuchuje.

W innych przypadkach interweniująca zapora ogniowa lub nawet sam zdalny host mogą „zapomnieć” o połączeniu TCP. Może się tak zdarzyć, jeśli nie wysyłasz żadnych danych przez długi czas (2 godziny to typowy limit czasu) lub ponieważ peer został ponownie uruchomiony i utracił informacje o aktywnych połączeniach. Wysłanie danych na jednym z tych niedziałających połączeń spowoduje również RST.


Aktualizacja w odpowiedzi na dodatkowe informacje:

Przyjrzyj się uważnie, jak obchodzisz się z SocketTimeoutException. Ten wyjątek jest zgłaszany, jeśli skonfigurowany limit czasu zostanie przekroczony podczas blokowania operacji gniazda. Stan samego gniazda nie jest zmieniany po zgłoszeniu tego wyjątku, ale jeśli program obsługi wyjątków zamknie gniazdo, a następnie spróbuje do niego zapisać, nastąpi zresetowanie połączenia. setSoTimeout()ma na celu zapewnienie prostego sposobu na wyrwanie się z read()operacji, która w innym przypadku mogłaby zostać zablokowana na zawsze, bez robienia brudnych rzeczy, takich jak zamykanie gniazda z innego wątku.

erickson
źródło
Nieprawidłowe pod kilkoma względami. Zarówno wyrzucanie elementów bezużytecznych, jak i zakończenie procesu powodują prawidłowe zamknięcie, a nie resetowanie, ale zamknięcie, po którym następuje zapis przez partnera, może wywołać reset zamiast EOS. SocketTimeoutExceptions są zgłaszane tylko wtedy, gdy czytnik ustawił limit czasu odczytu.
Markiz Lorne
I nie zawsze oznacza to, że otrzymano RST. Może to również oznaczać, że jeden został wygenerowany przez tę stronę.
Markiz Lorne,
17

Ilekroć mam takie dziwne problemy, zwykle siadam z narzędziem takim jak WireShark i patrzę na surowe dane przesyłane tam iz powrotem. Możesz być zaskoczony, gdy coś jest rozłączane, a powiadomienie jest wyświetlane tylko wtedy, gdy próbujesz czytać.

GEOCHET
źródło
9

Żenująco to powiedzieć, ale kiedy miałem ten problem, po prostu błędem było to, że zamykałem połączenie, zanim przeczytałem wszystkie dane. W przypadkach, gdy zwracano małe ciągi, działało, ale było to prawdopodobnie spowodowane tym, że cała odpowiedź była buforowana, zanim ją zamknąłem.

W przypadku zwracania większej ilości tekstu zgłaszany był wyjątek, ponieważ więcej niż wracał bufor.

Możesz sprawdzić, czy nie ma tego przeoczenia. Pamiętaj, że otwieranie adresu URL jest jak plik, pamiętaj, aby go zamknąć (zwolnić połączenie) po całkowitym przeczytaniu.

Scott S.
źródło
9

Powinieneś bardzo dokładnie sprawdzić pełny ślad,

Mam aplikację używającą gniazda serwera i naprawiłem java.net.SocketException: Connection resetprzypadek.

W moim przypadku dzieje się tak podczas odczytu z Socketobiektu clientSocket, który z jakiegoś powodu zamyka swoje połączenie. (Utrata sieci, awaria zapory lub aplikacji albo zamierzone zamknięcie)

Właściwie to przywracałem połączenie, gdy wystąpił błąd podczas odczytu z tego obiektu Socket.

Socket clientSocket = ServerSocket.accept();
is = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
int readed = is.read(); // WHERE ERROR STARTS !!!

Ciekawostką jest to, for my JAVA Socketże jeśli klient łączy się z my ServerSocketi zamyka swoje połączenie bez wysyłania jakichkolwiek is.read()wywołań rekurencyjnych, wydaje się, że będąc w nieskończonej pętli while do odczytu z tego gniazda, próbujesz odczytać z zamkniętego połączenia. Jeśli używasz czegoś takiego jak poniżej do operacji odczytu;

while(true)
{
  Receive();
}

Następnie dostajesz stos i śledzenie czegoś takiego jak poniżej

java.net.SocketException: Socket is closed
    at java.net.ServerSocket.accept(ServerSocket.java:494)

Po prostu zamknąłem ServerSocket i odnowiłem połączenie i czekałem na dalsze przychodzące połączenia klientów

String Receive() throws Exception
{
try {                   
            int readed = is.read();
           ....
}catch(Exception e)
{
        tryReConnect();
        logit(); //etc
}


//...
}

Spowoduje to ponowne nawiązanie połączenia w przypadku utraty nieznanego gniazda klienta

private void tryReConnect()
        {
            try
            {
                ServerSocket.close();
                //empty my old lost connection and let it get by garbage col. immediately 
                clientSocket=null;
                System.gc();
                //Wait a new client Socket connection and address this to my local variable
                clientSocket= ServerSocket.accept(); // Waiting for another Connection
                System.out.println("Connection established...");
            }catch (Exception e) {
                String message="ReConnect not successful "+e.getMessage();
                logit();//etc...
            }
        }

Nie mogłem znaleźć innego sposobu, ponieważ jak widać na poniższym obrazku, nie możesz zrozumieć, czy połączenie jest utracone, czy nie bez a try and catch, ponieważ wszystko wydaje się w porządku. Otrzymałem tę migawkę podczas Connection resetciągłego otrzymywania .

wprowadź opis obrazu tutaj

Davut Gürbüz
źródło
6

Miałem ten sam błąd. Znalazłem teraz rozwiązanie problemu. Problem polegał na tym, że program klienta kończył pracę, zanim serwer odczytał strumienie.

kml_ckr
źródło
Samo to nie spowodowałoby tego wyjątku.
Markiz Lorne
tak by się stało, gdyby System.exit (0) zabił program i nikt nie wywoła metody socket.close (), ponieważ połączenie jest w złym stanie i nie zostało poprawnie zamknięte. Więc bardziej poprawnie powiedział, że ma program kliencki, który wyłącza się bez zamykania gniazd;), co jest złą rzeczą i powinno zostać naprawione.
Dean Hiller
1
@DeanHiller Nie, nie byłoby. System operacyjny zamknie gniazdo w taki sam sposób, jak powinna to zrobić aplikacja.
Markiz Lorne
@EJP .... Nie jestem pewien ... Po prostu wiem, że możemy to odtworzyć za pomocą System.exit, ale nie pamiętam systemu operacyjnego / config, ponieważ było to całkiem dawno ... wywołanie funkcji socket.close ( ) na serwerze uniemożliwiło zresetowanie połączenia i działało bardziej poprawnie.
Dean Hiller
2
@DeanHiller Proces odczytu został zakończony przed zakończeniem procesu pisania.
Markiz Lorne
4

Miałem ten problem z systemem SOA napisanym w Javie. Uruchomiłem zarówno klienta, jak i serwer na różnych komputerach fizycznych i działały dobrze przez długi czas, a potem te paskudne resetowania połączenia pojawiły się w dzienniku klienta i nie było nic dziwnego w dzienniku serwera. Ponowne uruchomienie klienta i serwera nie rozwiązało problemu. W końcu odkryliśmy, że sterta po stronie serwera była raczej pełna, więc zwiększyliśmy pamięć dostępną dla maszyny JVM: problem rozwiązany! Zauważ, że w logu nie było OutOfMemoryError: pamięć była po prostu ograniczona, a nie wyczerpana.

Pino
źródło
2

Sprawdź wersję Java swojego serwera. Zdarzyło mi się to, ponieważ mój Weblogic 10.3.6 był na JDK 1.7.0_75, który był na TLSv1. Pozostały punkt końcowy, który próbowałem wykorzystać, wyłączał wszystko poniżej TLSv1.2.

Domyślnie Weblogic próbował wynegocjować najsilniejszy wspólny protokół. Zobacz szczegóły tutaj: Problemy z ustawieniem właściwości systemu https.protocols dla połączeń HTTPS .

Dodałem szczegółowe rejestrowanie SSL, aby zidentyfikować obsługiwane TLS. Oznacza to, że do uzgadniania używany był protokół TLSv1.
-Djavax.net.debug=ssl:handshake:verbose:keymanager:trustmanager -Djava.security.debug=access:stack

Rozwiązałem to, wypychając tę ​​funkcję do naszego produktu zgodnego z JDK8, JDK8 domyślnie ustawia TLSv1.2. W przypadku osób ograniczonych do JDK7 z powodzeniem przetestowałem również obejście dla Java 7, aktualizując do TLSv1.2. Użyłem tej odpowiedzi: Jak włączyć TLS 1.2 w Javie 7

Sumiya
źródło
wielkie dzięki, pokazujesz mi nowy kierunek rozwiązania mojego problemu. i wreszcie stwierdziłem, że tak jest !!!
karl li
1

Miałem również ten problem z programem Java, który próbował wysłać polecenie na serwer przez SSH. Problem dotyczył maszyny wykonującej kod Java. Nie miał uprawnień do łączenia się ze zdalnym serwerem. Metoda write () działała prawidłowo, ale metoda read () generowała java.net.SocketException: Connection reset. Rozwiązałem ten problem, dodając klucz SSH klienta do znanych kluczy zdalnego serwera.

pmartin8
źródło
0

Z mojego doświadczenia wynika, że ​​często napotykam następujące sytuacje;

  1. Jeśli pracujesz w firmie korporacyjnej, skontaktuj się z zespołem ds. Sieci i bezpieczeństwa. Ponieważ w żądaniach skierowanych do usług zewnętrznych może być konieczne udzielenie pozwolenia dla odpowiedniego punktu końcowego.

  2. Innym problemem jest to, że certyfikat SSL mógł wygasnąć na serwerze, na którym działa aplikacja.

bmck
źródło