web-dev-qa-db-fra.com

Comment réparer Java.net.SocketException: Broken pipe?

J'utilise le client HTTP commun Apache pour appeler l'URL à l'aide de la méthode post pour publier les paramètres. Il renvoie rarement l'erreur ci-dessous.

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)

Quelqu'un peut-il suggérer ce qui cause cette exception et comment le déboguer?

142
Mani

Ceci est causé par:

  • le plus souvent, l'écriture sur une connexion lorsque l'autre extrémité l'a déjà fermée;
  • moins généralement, l’homologue ferme la connexion sans lire toutes les données déjà en attente de son côté.

Donc, dans les deux cas, vous avez un protocole d'application mal défini ou implémenté.

Il y a une troisième raison que je ne décrirai pas ici mais qui implique que le pair prenne des mesures délibérées pour réinitialiser la connexion plutôt que de la fermer correctement.

74
user207421

Dans notre cas, nous avons connu cela en effectuant un test de charge sur notre serveur d'applications. Le problème s'est avéré que nous devions ajouter de la mémoire supplémentaire à notre machine virtuelle Java, car celle-ci s'épuisait. Cela a résolu le problème.

Essayez d'augmenter la mémoire disponible pour la machine virtuelle Java et ou surveillez l'utilisation de la mémoire lorsque vous obtenez ces erreurs.

29
Dave

SocketException: le tube cassé est causé par la fermeture de la connexion par l'autre extrémité (le client ou le serveur) pendant que votre code lit ou écrit sur la connexion.

Il s'agit d'une exception très courante dans les applications client/serveur qui reçoivent du trafic de clients ou de serveurs en dehors du contrôle des applications. Par exemple, le client est un navigateur. Si le navigateur passe un appel Ajax et/ou si l'utilisateur ferme simplement la page ou le navigateur, cela peut tuer toutes les communications de manière inattendue. Fondamentalement, vous verrez cette erreur chaque fois que l’autre extrémité met fin à leur application et vous ne l’anticipiez pas.

Si vous rencontrez cette exception dans votre application, cela signifie que vous devez vérifier votre code à l'endroit où le IO (entrée/sortie) se produit et l'envelopper avec un bloc try/catch pour intercepter cette exception IOException. Il vous appartient ensuite de décider de la manière dont vous souhaitez gérer cette situation semi-valide.

Dans votre cas, le premier endroit où vous avez toujours le contrôle est l'appel à HttpMethodDirector.executeWithRetry - Assurez-vous donc que l'appel est encapsulé avec le bloc try/catch et gérez-le comme bon vous semble.

Je vous déconseille vivement de consigner les erreurs spécifiques à SocketException-Broken Pipe à des niveaux autres que les niveaux de débogage/trace. Sinon, cela peut être utilisé comme une forme d'attaque DOS (Denial Of Service) en remplissant les journaux. Essayez de durcir et de tester négativement votre application pour ce scénario courant.

7
AndyGee

Tous les flux et toutes les connexions ouverts doivent être correctement fermés. Ainsi, lors de notre prochaine tentative d'utilisation de l'objet urlConnection, aucune erreur ne sera renvoyée. Par exemple, le changement de code suivant a corrigé l'erreur pour moi.

Avant:

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

Après:

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.
4
Murali Mohan

J'ai implémenté la fonctionnalité de téléchargement de données via un serveur FTP et y ai trouvé la même exception lors de la reprise du téléchargement. Pour résoudre cette exception, vous devrez toujours vous déconnecter de la session précédente et créer une nouvelle instance du client et une nouvelle connexion avec le serveur. Cette même approche pourrait également être utile pour HTTPClient.

1
Naeem Ahmad

Les réponses ci-dessus illustrent la raison de ce Java.net.SocketException: Broken pipe: l'autre extrémité a fermé la connexion. Je voudrais partager l'expérience de ce qui s'est passé quand je l'ai rencontré:

  1. dans la requête d'un client, l'en-tête Content-Type est définie par erreur comme étant plus grande que le corps de la requête (en fait, il n'y avait aucun corps)
  2. le service de base de la prise Tomcat attendait des données de cette taille (http est sur TCP, ce qui garantit la livraison en encapsulant et ...)
  3. à l'expiration du délai de 60 secondes, Tomcat lève une exception de délai d'expiration: Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception Java.net.SocketTimeoutException: null
  4. le client reçoit une réponse avec le code d'état 500 en raison de l'exception de délai d'expiration.
  5. connexion proche du client (car il reçoit une réponse).
  6. Tomcat jette Java.net.SocketException: Broken pipe parce que le client l'a fermé.

Parfois, Tomcat ne lance pas une exception pip cassée, car une exception de délai d'attente ferme la connexion, ce qui explique pourquoi une telle différence me trouble également.

0
Tiina

Le problème peut être que vos fichiers déployés ne sont pas mis à jour avec les méthodes RMI correctes. Vérifiez que votre interface RMI a mis à jour les paramètres ou les structures de données mises à jour que votre client n'a pas. Ou que votre client RMI n'a pas de paramètre différent de celui de votre version de serveur.

Ceci est juste une supposition éclairée. Après avoir redéployé les fichiers de classe de mon application serveur et effectué de nouveaux tests, le problème du "canal cassé" a disparu.

0
JonAar Livernois

La raison en est que l'homologue distant ferme son socket (plantage par exemple). Par conséquent, si vous essayez de lui écrire des données, vous l'obtiendrez. pour résoudre ce problème, protégez les opérations de lecture/écriture sur le socket entre (essayez catch), puis gérez le cas de perte de connexion dans le catch (renouvellement de la connexion, arrêt du programme, ...):

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