Jak naprawić java.net.SocketException: uszkodzony potok?


Używam klienta http apache commons do wywoływania adresu URL z metodą post do wysyłania parametrów i rzadko daje to poniższy błąd.
java.net.SocketException: Broken pipe
at java.net.SocketOutputStream.socketWrite0(Native Method)
at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:92)
at java.net.SocketOutputStream.write(SocketOutputStream.java:136)
at java.io.BufferedOutputStream.write(BufferedOutputStream.java:105)
at java.io.FilterOutputStream.write(FilterOutputStream.java:80)
at org.apache.commons.httpclient.methods.ByteArrayRequestEntity.writeRequest(ByteArrayRequestEntity.java:90)
at org.apache.commons.httpclient.methods.EntityEnclosingMethod.writeRequestBody(EntityEnclosingMethod.java:499)
at org.apache.commons.httpclient.HttpMethodBase.writeRequest(HttpMethodBase.java:2114)
at org.apache.commons.httpclient.HttpMethodBase.execute(HttpMethodBase.java:1096)
at org.apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.java:398)

Czy ktoś może zasugerować, co powoduje ten wyjątek i jak go debugować?
Zaproszony:
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

To dlatego, że:
  • Zazwyczaj połączenie jest zapisywane, gdy drugi koniec już je zamknął;
  • rzadziej peer zamyka połączenie bez odczytywania żadnych danych, które już oczekują na jego zakończenie.

Tak więc w obu przypadkach masz źle zdefiniowany lub zaimplementowany protokół aplikacji.
Jest trzeci powód, którego tutaj nie będę dokumentować, ale który polega na tym, że peer podejmuje celowe działania w celu ponownego uruchomienia, zamiast prawidłowego zamykania połączenia.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

W naszym przypadku doświadczyliśmy tego podczas testu obciążenia na naszym serwerze aplikacji. Problem polegał na tym, że musieliśmy dodać dodatkową pamięć do naszej maszyny JVM, ponieważ kończyła się. To rozwiązało problem.
Spróbuj zwiększyć ilość pamięci dostępnej dla maszyny JVM i/lub monitoruj użycie pamięci, gdy wystąpią te błędy.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

SocketException: Przerwany potok spowodowany zamknięciem połączenia przez „drugi koniec” (klient lub serwer), gdy kod odczytuje z połączenia lub zapisuje do niego.
Jest to bardzo częsty wyjątek w aplikacjach typu klient/serwer, które odbierają ruch od klientów lub serwerów poza kontrolą aplikacji. Na przykład klient jest przeglądarką. Jeśli przeglądarka wykona połączenie Ajax i/lub użytkownik po prostu zamknie stronę lub przeglądarkę, może skutecznie nieoczekiwanie przerwać całą komunikację. Zasadniczo zobaczysz ten błąd za każdym razem, gdy drugi koniec wyjdzie ze swojej aplikacji, a tego się nie spodziewałeś.
Jeśli napotkasz ten wyjątek w swojej aplikacji, oznacza to, że powinieneś sprawdzić kod, w którym dzieje się IO (wejście/wyjście) i zawinąć go blokiem try/catch, aby złapać ten IOException. To wtedy decydujesz, jak chcesz sobie poradzić z tą na wpół wyimaginowaną sytuacją.
W twoim przypadku najwcześniejszym miejscem, nad którym nadal masz kontrolę, jest wywołanie
HttpMethodDirector.executeWithRetry
- więc upewnij się, że zawinąłeś wywołanie w bloku try/catch i obsłużono je w dowolny sposób.
Zdecydowanie odradzam rejestrowanie błędów specyficznych dla SocketException-Broken Pipe na jakimkolwiek poziomie innym niż debug/trace. Może również służyć jako forma ataku DOS (Denial of Service) poprzez wypełnianie dzienników. Spróbuj wzmocnić i negatywnie przetestować aplikację pod kątem tego typowego scenariusza.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Wszystkie otwarte strumienie & amp; połączenia muszą być poprawnie zamknięte, więc przy kolejnej próbie użycia obiektu urlConnection nie wyświetli się błąd. Na przykład następująca zmiana kodu naprawiła ten błąd.
Przed:
OutputStream out = new BufferedOutputStream(urlConnection.getOutputStream());
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(out));
bw.write("Some text");
bw.close();
out.close();

Po:
OutputStream os = urlConnection.getOutputStream();
OutputStream out = new BufferedOutputStream(os);
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(out));
bw.write("Some text");
bw.close();
out.close();
os.close();// This is a must.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Zaimplementowałem funkcję przesyłania danych przez serwer FTP i znalazłem tam ten sam wyjątek podczas wznawiania przesyłania.
Aby rozwiązać ten wyjątek, zawsze musisz rozłączyć się z poprzednią sesją i utworzyć nową instancję klienta oraz nowe połączenie z serwerem. To samo podejście może być również przydatne w przypadku klienta HTTPClient.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Miałem ten sam problem, kiedy tworzyłem prostą aplikację Java, która nasłuchuje określonego protokołu TCP. Zwykle nie miałem żadnych problemów, ale kiedy przeprowadziłem jakiś test warunków skrajnych, zauważyłem, że jakiś rodzaj połączenia został zerwany z błędem
socket write wyjątek
.
Po zbadaniu sprawy znalazłem rozwiązanie, które rozwiązuje mój problem. Wiem, że to pytanie jest dość stare, ale wolę podzielić się moim rozwiązaniem, ktoś może uznać je za przydatne.
Problem polegał na utworzeniu ServerSocket. Czytałem z dokumentacji, że jest limit 50 gniazd. Jeśli spróbujesz otworzyć inne połączenie, zostaną one odrzucone. Rozwiązaniem jest po prostu zmiana tej domyślnej konfiguracji po stronie serwera. W poniższym przypadku tworzę serwer gniazd, który nasłuchuje na porcie TCP
10_000
i akceptuje maksymalnie
200
oczekujących gniazd.
<pre class="lang-java prettyprint-override">
new Thread(() -> {
try (ServerSocket serverSocket = new ServerSocket(10_000, 200)) {
logger.info("Server starts listening on TCP port {}", port); while (true) {
try {
ClientHandler clientHandler = clientHandlerProvider.getObject(serverSocket.accept(), this);
executor.execute(clientHandler::start);
} catch (Exception e) {
logger.error(e.getMessage());
}
} } catch (IOException | SecurityException | IllegalArgumentException e) {
logger.error("Could not open server on TCP port {}. Reason: {}", port, e.getMessage());
}
}).start();

Z Javadoc z

ServerSocket
https://docs.oracle.com/javase ... .html
:

Maksymalna długość kolejki do wskazywania połączenia przychodzącego (żądania połączenia) jest ustawiana w parametrze backlog. Jeśli wskazanie połączenia pojawia się, gdy kolejka jest pełna, połączenie jest odrzucane.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Problem może polegać na tym, że wdrożone pliki nie są aktualizowane przy użyciu poprawnych metod RMI. Sprawdź, czy Twój RMI ma zaktualizowane parametry lub zaktualizowane struktury danych, których nie ma Twój klient. Albo że twój klient RMI nie ma opcji innych niż te, które ma twoja wersja serwera.
To tylko zgadywanie. Po ponownym wdrożeniu plików klas aplikacji serwera i ponownym przetestowaniu problem „Uszkodzony potok” zniknął.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Powyższe odpowiedzi ilustrują przyczynę tego
java.net.SocketException: Broken pipe
: drugi koniec zamknął połączenie. Chciałbym podzielić się doświadczeniem z tego, co się stało, kiedy na to wpadłem:
  • w żądaniu klienta nagłówek
    Content-Type
    jest omyłkowo ustawiony jako większy niż w rzeczywistości treść żądania (w rzeczywistości nie było jej wcale)
  • dolna usługa na gnieździe tomcat czekała na dane o tym rozmiarze ciała (http jest na TCP, który zapewnia dostarczanie przez hermetyzację i ...)
  • po upływie 60 sekund tomcat zgłasza wyjątek limitu czasu: Servlet.service () dla serwletu [dispatcherServlet] w kontekście ze ścieżką [] zgłosił wyjątek java.net.SocketTimeoutException: null
  • klient otrzymuje odpowiedź z kodem statusu 500 z powodu wyjątku limitu czasu.
  • klient zamyka połączenie (ponieważ otrzymuje odpowiedź).
  • tomcat zgłasza
    java.net.SocketException: Broken pipe
    , ponieważ klient go zamknął.

Czasami tomcat nie zgłasza zepsutego wyjątku pip, ponieważ wyjątek timeout zamyka połączenie, dlaczego taka różnica też mnie dezorientuje.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

JavaDoc:
Maksymalna długość kolejki do wskazania połączenia przychodzącego (a
żądanie połączenia) jest ustawiona na 50. Jeśli pojawi się wskazanie połączenia
gdy kolejka jest pełna, połączenie jest odrzucane.

Na przykład należy zwiększyć parametr „backlog” swojego ServerSocket
int backlogSize = 50 ;
new ServerSocket(port, backlogSize);
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Powodem jest to, że zdalny host zamyka swoje gniazdo (na przykład awaria), więc jeśli na przykład spróbujesz zapisać w nim dane, otrzymasz to. aby rozwiązać ten problem, zabezpiecz operacje odczytu/zapisu do gniazda pomiędzy (spróbuj catch), a następnie zarządzaj przypadkiem utraty połączenia w catch (odnów połączenie, zatrzymaj program, ... itd.):
try {
/* your code */
} catch (SocketException e) {
e.printStackTrace();
/* insert your failure processings here */
}

Aby odpowiedzieć na pytania, Zaloguj się lub Zarejestruj się