Hoe java.net.SocketException: Gebroken pijp te repareren?

Ik gebruik de apache commons http-client om de url aan te roepen met de post-methode om de parameters te posten en het geeft zelden de onderstaande fout.

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)

Kan iemand aangeven wat deze uitzondering veroorzaakt en hoe deze te debuggen?


Antwoord 1, autoriteit 100%

Dit wordt veroorzaakt door:

  • meestal schrijven naar een verbinding wanneer de andere kant deze al heeft gesloten;
  • minder gebruikelijk is dat de peer de verbinding verbreekt zonder alle gegevens te lezen die al in behandeling zijn aan zijn kant.

Dus in beide gevallen heb je een slecht gedefinieerd of geïmplementeerd applicatieprotocol.

Er is een derde reden die ik hier niet zal documenteren, maar die inhoudt dat de peer opzettelijk actie onderneemt om de verbinding te resetten in plaats van de verbinding correct te sluiten.


Antwoord 2, autoriteit 45%

In ons geval hebben we dit ervaren tijdens het uitvoeren van een laadtest op onze app-server. Het probleem bleek dat we extra herinnering aan onze JVM moeten toevoegen omdat het opraakte. Dit heeft het probleem opgelost.

Probeer het geheugen te vergroten dat beschikbaar is voor de JVM en of bewaak het geheugengebruik wanneer u die fouten krijgt.


Antwoord 3, Autoriteit 11%

SocketException: Broken Pipe, wordt veroorzaakt door het ‘andere uiteinde’ (de client of de server) die de verbinding sluiten terwijl uw code is gelezen van of schrijven naar de verbinding.

Dit is een zeer gebruikelijke uitzondering in client / server-applicaties die verkeer van klanten of servers ontvangen buiten de toepassingscontrole. De klant is bijvoorbeeld een browser. Als de browser een AJAX-oproep maakt, en / of de gebruiker simpelweg de pagina of browser sluit, kan dit effectief alle communicatie onverwachts doden. Kortom, u ziet deze fout op elk gewenst moment dat het andere uiteinde hun aanvraag beëindigt en u niet verwachtte.

Als u deze uitzondering in uw toepassing ervaart, betekent dit dat u uw code moet controleren waar de IO (INPUT / OUTPUT) optreedt en wikkelt deze met een poging / vangstblok om deze IOException te vangen. Het is dan, aan u om te beslissen hoe u deze semi-geldige situatie wilt verwerken.

In uw geval, de vroegste plaats waar u nog steeds controle hebt, is de oproep naar HttpMethodDirector.executeWithRetry– Zorg ervoor dat de oproep is gewikkeld met het poging / vangstblok en hanteer het hoe u de pasvorm kunt hanteren .

Ik zou sterk adviseren tegen logging-socketException-gebroken pijpspecifieke fouten op iets anders dan debug / traceerniveaus. Anders kan dit worden gebruikt als een vorm van DOS (Denial of Service) Attack door de logboeken in te vullen. Probeer en negatieve test uw aanvraag voor dit gemeenschappelijke scenario.


Antwoord 4, Autoriteit 6%

Alle open streams & verbindingen moeten correct worden gesloten, dus de volgende keer dat we het urlConnection-object proberen te gebruiken, wordt er geen fout gegenereerd. Als voorbeeld heeft de volgende codewijziging de fout voor mij verholpen.

Vroeger:

OutputStream out = new BufferedOutputStream(urlConnection.getOutputStream());
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(out));
bw.write("Some text");
bw.close();
out.close();

Na:

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.

Antwoord 5, autoriteit 2%

Ik had hetzelfde probleem toen ik een eenvoudige Java-toepassing aan het ontwikkelen was die luistert op een specifiek TCP. Meestal had ik geen probleem, maar toen ik een stresstest uitvoerde, merkte ik dat een verbinding brak met de fout socket write exception.

Na onderzoek heb ik een oplossing gevonden die mijn probleem oplost. Ik weet dat deze vraag vrij oud is, maar ik deel liever mijn oplossing, iemand kan het nuttig vinden.

Het probleem was bij het maken van ServerSocket. Ik las uit Javadoc dat er een standaardlimiet is van 50 in behandeling zijnde sockets. Als u probeert een andere verbinding te openen, worden deze geweigerd. De oplossing bestaat eenvoudigweg in het wijzigen van deze standaardconfiguratie aan de serverzijde. In het volgende geval maak ik een Socket-server die luistert op TCP-poort 10_000en maximaal 200in behandeling zijnde sockets accepteert.

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();

Van Javadoc van ServerSocket:

De maximale wachtrijlengte voor inkomende verbindingsindicaties (een verzoek om verbinding te maken) is ingesteld op de backlog-parameter. Als een verbindingsindicatie arriveert wanneer de wachtrij vol is, wordt de verbinding geweigerd.


Antwoord 6

Ik heb de functionaliteit voor het downloaden van gegevens geïmplementeerd via de FTP-server en vond daar dezelfde uitzondering toen ik die download hervatte.
Om deze uitzondering op te lossen, moet u altijd de verbinding met de vorige sessie verbreken en een nieuw exemplaar van de Client en een nieuwe verbinding met de server maken. Deze zelfde aanpak kan ook nuttig zijn voor HTTPClient.


Antwoord 7

Het probleem kan zijn dat uw geïmplementeerde bestanden niet zijn bijgewerkt met de juiste RMI-methoden. Controleer of uw RMI-interface bijgewerkte parameters heeft of bijgewerkte gegevensstructuren die uw client niet heeft. Of dat uw RMI-client geen parameters heeft die verschillen van uw serverversie.

Dit is slechts een gefundeerde gok. Nadat ik de klassebestanden van mijn servertoepassing opnieuw had geïmplementeerd en opnieuw had getest, was het probleem van “Broken pipe” verdwenen.


Antwoord 8

De bovenstaande antwoorden illustreren de reden voor deze java.net.SocketException: Broken pipe: het andere uiteinde sloot de verbinding. Ik wil graag mijn ervaring delen wat er gebeurde toen ik het tegenkwam:

  1. in het verzoek van een klant is de kop Content-Typeten onrechte groter ingesteld dan de hoofdtekst van de aanvraag (in feite was er helemaal geen hoofdtekst)
  2. de onderste service in de tomcat-socket wachtte op body-gegevens van dat formaat (http staat op TCP, wat zorgt voor levering door inkapseling en …)
  3. wanneer 60 seconden zijn verstreken, gooit kater een time-outuitzondering:
    Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception
    java.net.SocketTimeoutException: null
  4. klant ontvangt een reactie met statuscode 500 vanwege de time-outuitzondering.
  5. klant hechte verbinding (omdat het antwoord ontvangt).
  6. tomcat gooit java.net.SocketException: Broken pipeomdat de client deze heeft gesloten.

Soms gooit Tomcat geen gebroken pip-uitzondering, omdat een time-outuitzondering de verbinding verbreekt, waarom zo’n verschil mij ook in verwarring brengt.


Antwoord 9

Ik merkte dat ik de verkeerde URL voor het HTTP-verzoek gebruikte tijdens het maken, wat ik later heb gewijzigd dat het mijn probleem oploste. mijn upload-url was: http://192.168.0.31:5000/uploaderterwijl ik http://192.168.0.31:5000. dat was een telefoontje. en kreeg een java.net.SocketException: Gebroken pijp? uitzondering.

Dat was mijn reden. kan ertoe leiden dat u nog een punt moet controleren wanneer dit probleem

 public void postRequest()  {
        Security.insertProviderAt(Conscrypt.newProvider(), 1);
        System.out.println("mediafilename-->>" + mediaFileName);
        String[] dirarray = mediaFileName.split("/");
        String file_name = dirarray[6];
        //Thread.sleep(10000);
        RequestBody requestBody = new MultipartBody.Builder()
                    .setType(MultipartBody.FORM)
                    .addFormDataPart("file",file_name, RequestBody.create(MediaType.parse("video/mp4"), new File(mediaFileName))).build();
        OkHttpClient okHttpClient = new OkHttpClient();
//        ExecutorService executor = newFixedThreadPool(20);
//        Request request = new Request.Builder().post(requestBody).url("https://192.168.0.31:5000/uploader").build();
        Request request = new Request.Builder().url("https://192.168.0.31:5000/uploader").post(requestBody).build();
//        Request request = new Request.Builder().url("https://192.168.0.31:5000").build();
        okHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(@NotNull Call call, @NotNull IOException e) {
//
                call.cancel();
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(getApplicationContext(),"Something went wrong:" + " ", Toast.LENGTH_SHORT).show();
                    }
                });
                e.printStackTrace();
            }
            @Override
            public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            System.out.println(response.body().string());
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                });
                System.out.println("Response ; " + response.body().toString());
//                Toast.makeText(getApplicationContext(), response.body().toString(),Toast.LENGTH_LONG).show();
                System.out.println(response);
            }
        });

Antwoord 10

JavaDoc:

De maximale wachtrijlengte voor inkomende verbindingsindicaties (a
verzoek om verbinding te maken) is ingesteld op 50. Als een verbindingsindicatie arriveert
wanneer de wachtrij vol is, wordt de verbinding geweigerd.

U zou bijvoorbeeld de “backlog” parameter van uw ServerSocket moeten verhogen

int backlogSize = 50 ;
new ServerSocket(port, backlogSize);

Antwoord 11

De oorzaak is dat de externe peer zijn socket sluit (crash bijvoorbeeld), dus als je bijvoorbeeld gegevens naar hem probeert te schrijven, krijg je dit. om dat op te lossen, beveiligt u lees-/schrijfbewerkingen naar socket-bewerkingen tussen (probeer catch), en beheer vervolgens het geval van de verloren verbinding in de vangst (vernieuw de verbinding, stop het programma, … enz.):

try {
      /* your code */
 } catch (SocketException e) {
      e.printStackTrace();
      /* insert your failure processings here */
 }

Other episodes