java.net.SocketException: réinitialisation de la connexion

128

J'obtiens l'erreur suivante en essayant de lire à partir d'une socket. Je fais un readInt()sur çaInputStream , et j'obtiens cette erreur. En parcourant la documentation, cela suggère que la partie cliente de la connexion a fermé la connexion. Dans ce scénario, je suis le serveur.

J'ai accès aux fichiers journaux du client et il ne ferme pas la connexion, et en fait, ses fichiers journaux suggèrent que je ferme la connexion. Alors, quelqu'un a-t-il une idée de pourquoi cela se produit? Que vérifier d'autre? Cela se produit-il lorsque des ressources locales atteignent peut-être des seuils?


Je note que j'ai la ligne suivante:

socket.setSoTimeout(10000);

juste avant le readInt() . Il y a une raison à cela (longue histoire), mais curieux, y a-t-il des circonstances dans lesquelles cela pourrait conduire à l'erreur indiquée? J'ai le serveur en cours d'exécution dans mon IDE, et il m'est arrivé de laisser mon IDE bloqué sur un point d'arrêt, et j'ai alors remarqué que les mêmes erreurs commençaient exactement à apparaître dans mes propres journaux dans mon IDE.

Quoi qu'il en soit, en le mentionnant simplement, j'espère que ce n'est pas un hareng rouge. :-(

bleuâtre
la source
Avez-vous des traces de pile des deux côtés? Pouvez-vous décrire un peu plus l'architecture du réseau? (Sur Internet sauvage? Sur la même machine? Quelque part entre les deux?) Cela arrive-t-il tout le temps? Ou par intermittence?
Stu Thompson

Réponses:

116

Il existe plusieurs causes possibles.

  1. L'autre extrémité a délibérément réinitialisé la connexion, d'une manière que je ne documenterai pas ici. Il est rare, et généralement incorrect, pour les logiciels d'application de faire cela, mais cela n'est pas inconnu pour les logiciels commerciaux.

  2. Plus couramment, cela est causé par l'écriture sur une connexion que l'autre extrémité a déjà fermée normalement. En d'autres termes, une erreur de protocole d'application.

  3. Cela peut également être dû à la fermeture d'un socket lorsqu'il y a des données non lues dans le tampon de réception du socket.

  4. Sous Windows, «le logiciel a provoqué l'abandon de la connexion», qui n'est pas la même chose que «la réinitialisation de la connexion», est causé par des problèmes de réseau envoyés depuis votre extrémité. Il existe un article de la base de connaissances Microsoft à ce sujet.

Marquis de Lorne
la source
@MattLyons Merci. Il existe de bien meilleurs articles MSDN que cela. Franchement, je trouve cela difficile à croire. Une connexion n'existera même pas tant que les adresses IP source et cible correctes n'auront pas été établies. Les articles MSDN que j'ai vus font référence à des erreurs réseau persistantes qui expirent la connexion.
Marquis de Lorne
48

La réinitialisation de la connexion signifie simplement qu'un TCP RST a été reçu. Cela se produit lorsque votre pair reçoit des données qu'il ne peut pas traiter, et il peut y avoir plusieurs raisons à cela.

Le plus simple est lorsque vous fermez le socket, puis écrivez plus de données sur le flux de sortie. En fermant le socket, vous avez dit à votre pair que vous avez fini de parler, et il peut oublier votre connexion. Lorsque vous envoyez de toute façon plus de données sur ce flux, le pair le rejette avec un RST pour vous faire savoir qu'il n'écoute pas.

Dans d'autres cas, un pare-feu intervenant ou même l'hôte distant lui-même peut "oublier" votre connexion TCP. Cela peut se produire si vous n'envoyez aucune donnée pendant une longue période (2 heures est un délai d'attente courant), ou parce que l'homologue a été redémarré et a perdu ses informations sur les connexions actives. L'envoi de données sur l'une de ces connexions défaillantes entraînera également un RST.


Mise à jour en réponse à des informations supplémentaires:

Regardez de près votre manipulation du SocketTimeoutException. Cette exception est déclenchée si le délai d'expiration configuré est dépassé alors qu'il est bloqué sur une opération de socket. L'état du socket lui-même n'est pas modifié lorsque cette exception est levée, mais si votre gestionnaire d'exceptions ferme le socket, puis essaie d'y écrire, vous serez dans une condition de réinitialisation de connexion. setSoTimeout()est destiné à vous donner un moyen propre de sortir d'une read()opération qui pourrait autrement bloquer pour toujours, sans faire des choses sales comme la fermeture du socket d'un autre thread.

Erickson
la source
Pas correct à plusieurs égards. Le ramassage des ordures et les sorties de processus provoquent des fermetures correctes, pas des réinitialisations, mais une fermeture suivie d'une écriture par le pair peut induire une réinitialisation plutôt qu'un EOS. Les exceptions SocketTimeoutExceptions ne sont déclenchées que si le lecteur a défini un délai de lecture.
Marquis of Lorne
Et cela ne signifie pas toujours qu'une TVD a été reçue. Cela peut également signifier qu'un a été généré par ce côté.
Marquis de Lorne
17

Chaque fois que j'ai eu des problèmes étranges comme celui-ci, je m'assois généralement avec un outil comme WireShark et regarde les données brutes qui sont transmises. Vous pourriez être surpris de savoir où les choses sont déconnectées et vous n'êtes averti que lorsque vous essayez de lire.

GEOCHET
la source
9

C'est embarrassant de le dire, mais quand j'ai eu ce problème, c'était simplement une erreur que je fermais la connexion avant de lire toutes les données. Dans les cas où de petites chaînes étaient renvoyées, cela fonctionnait, mais cela était probablement dû au fait que toute la réponse était mise en mémoire tampon, avant de la fermer.

Dans les cas où des quantités de texte plus longues étaient renvoyées, l'exception était levée, car plus d'un tampon revenait.

Vous pourriez vérifier cet oubli. N'oubliez pas que l'ouverture d'une URL est comme un fichier, assurez-vous de la fermer (relâchez la connexion) une fois qu'elle a été entièrement lue.

Scott S
la source
9

Vous devez inspecter la trace complète très attentivement,

J'ai une application de socket serveur et j'ai corrigé un java.net.SocketException: Connection resetcas.

Dans mon cas, cela se produit lors de la lecture d'un Socketobjet clientSocket qui ferme sa connexion pour une raison quelconque. (Réseau perdu, pare-feu ou panne d'application ou fermeture prévue)

En fait, je rétablissais la connexion lorsque j'ai eu une erreur lors de la lecture de cet objet Socket.

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

La chose intéressante est que for my JAVA Socketsi un client se connecte à my ServerSocketet ferme sa connexion sans rien envoyer, il is.read()s'appelle lui-même de manière récursive. Si vous utilisez quelque chose comme ci-dessous pour l'opération de lecture;

while(true)
{
  Receive();
}

Ensuite, vous obtenez un stackTrace quelque chose comme ci-dessous encore et encore

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

Ce que j'ai fait, c'est simplement fermer ServerSocket, renouveler ma connexion et attendre d'autres connexions client entrantes

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


//...
}

Cela rétablit ma connexion pour les pertes de socket client inconnues

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...
            }
        }

Je n'ai pas pu trouver d'autre moyen car, comme vous le voyez dans l'image ci-dessous, vous ne pouvez pas comprendre si la connexion est perdue ou non sans un try and catch, car tout semble correct. J'ai eu cet instantané pendant que je recevais Connection resetcontinuellement.

entrez la description de l'image ici

Davut Gürbüz
la source
6

J'ai eu la même erreur. J'ai trouvé la solution au problème maintenant. Le problème était que le programme client se terminait avant que le serveur ne lise les flux.

kml_ckr
la source
Cela ne provoquerait pas à lui seul cette exception.
Marquis of Lorne
ce serait le cas si System.exit (0) tue le programme et que personne n'appelle socket.close () car la connexion est dans un mauvais état et n'a pas été fermée correctement. sooo plus correctement dit qu'il avait un programme client qui s'arrêtait sans fermer les sockets;) ce qui est une mauvaise chose et devrait être corrigé.
Dean Hiller
1
@DeanHiller Non, ce ne serait pas le cas. Le système d'exploitation fermerait le socket de la même manière que l'application devrait avoir.
Marquis de Lorne
@EJP .... Je ne suis pas sûr ... Je sais juste que nous pourrions le reproduire avec System.exit mais je ne me souviens pas du système d'exploitation / config car c'était il y a un certain temps .... appeler socket.close ( ) sur le serveur a empêché la réinitialisation de la connexion et il s'est comporté plus correctement.
Dean Hiller
2
@DeanHiller Le processus de lecture s'est terminé avant la fin du processus d'écriture.
Marquis de Lorne
4

J'ai eu ce problème avec un système SOA écrit en Java. J'exécutais à la fois le client et le serveur sur différentes machines physiques et ils ont bien fonctionné pendant longtemps, puis ces réinitialisations de connexion désagréables sont apparues dans le journal du client et il n'y avait rien d'étrange dans le journal du serveur. Le redémarrage du client et du serveur n'a pas résolu le problème. Finalement nous avons découvert que le tas côté serveur était plutôt plein donc nous avons augmenté la mémoire disponible pour la JVM: problème résolu! Notez qu'il n'y avait pas OutOfMemoryError dans le journal: la mémoire était simplement rare, pas épuisée.

Pino
la source
2

Vérifiez la version Java de votre serveur. Cela m'est arrivé parce que mon Weblogic 10.3.6 était sur JDK 1.7.0_75 qui était sur TLSv1. Le point de terminaison de repos que j'essayais de consommer était de fermer tout ce qui était en dessous de TLSv1.2.

Par défaut, Weblogic essayait de négocier le protocole partagé le plus puissant. Voir les détails ici: Problèmes avec la définition de la propriété système https.protocols pour les connexions HTTPS .

J'ai ajouté une journalisation SSL détaillée pour identifier le TLS pris en charge. Cela indiquait que TLSv1 était utilisé pour la prise de contact.
-Djavax.net.debug=ssl:handshake:verbose:keymanager:trustmanager -Djava.security.debug=access:stack

J'ai résolu ce problème en poussant la fonctionnalité sur notre produit compatible JDK8, JDK8 utilise par défaut TLSv1.2. Pour ceux qui sont limités à JDK7, j'ai également testé avec succès une solution de contournement pour Java 7 en mettant à niveau vers TLSv1.2. J'ai utilisé cette réponse: Comment activer TLS 1.2 dans Java 7

Sumiya
la source
merci beaucoup, vous me montrez une nouvelle direction pour résoudre mon problème. et enfin j'ai trouvé que c'est le cas !!!
karl li
1

J'ai également eu ce problème avec un programme Java essayant d'envoyer une commande sur un serveur via SSH. Le problème venait de la machine exécutant le code Java. Il n'avait pas l'autorisation de se connecter au serveur distant. La méthode write () fonctionnait bien, mais la méthode read () lançait une exception java.net.SocketException: Connection reset. J'ai résolu ce problème en ajoutant la clé SSH du client aux clés connues du serveur distant.

pmartin8
la source
0

Dans mon expérience, je rencontre souvent les situations suivantes;

  1. Si vous travaillez dans une entreprise, contactez l'équipe réseau et sécurité. Parce que dans les demandes adressées à des services externes, il peut être nécessaire de donner l'autorisation pour le point de terminaison concerné.

  2. Un autre problème est que le certificat SSL a peut-être expiré sur le serveur sur lequel votre application s'exécute.

bmck
la source