web-dev-qa-db-fra.com

Java NIO: que signifie IOException: canal cassé?)

Pour certaines de mes Java connexions NIO, lorsque j’ai un appel SocketChannel.write(ByteBuffer)], un IOException: "canal cassé" est lancé.

Qu'est-ce qui cause un "tuyau cassé" et, plus important encore, est-il possible de se remettre de cet état? S'il ne peut pas être récupéré, cela semble être un bon signe qu'un problème irréversible s'est produit et que je devrais simplement fermer cette connexion de socket. Est-ce une hypothèse raisonnable? Y a-t-il un moment où ceci IOException se produirait alors que la connexion socket était toujours correctement connectée (plutôt qu'une connexion fonctionnelle qui a échoué à un moment donné)?

Par ailleurs, est-il sage de toujours appeler SocketChannel.isConnected() avant de tenter une SocketChannel.write(), et si oui, puis-je également supposer que la connexion est "interrompue" et doit être fermée si SocketChannel.isConnected() et SocketChannel.isConnectionPending() sont tous deux false?

Merci!

87
DivideByHero

Qu'est-ce qui cause un "tuyau cassé" et, plus important encore, est-il possible de se remettre de cet état?

Cela est dû à quelque chose qui provoque la fermeture de la connexion. (Ce n'est pas votre application qui a fermé la connexion: cela aurait entraîné une exception différente.)

Il n'est pas possible de rétablir la connexion. Vous devez en ouvrir un nouveau.

S'il ne peut pas être récupéré, cela semble être un bon signe qu'un problème irréversible s'est produit et que je devrais simplement fermer cette connexion de socket. Est-ce une hypothèse raisonnable?

Oui, ça l'est. Une fois que vous avez reçu cette exception, le socket ne fonctionnera plus. La fermer est la seule chose sensée à faire.

Y a-t-il un moment où ceci IOException se produirait alors que la connexion de socket était toujours correctement connectée (plutôt qu'une connexion fonctionnelle qui a échoué à un moment donné)?

Non (ou du moins, pas sans renverser le comportement correct de la pile réseau du système d'exploitation, de la machine virtuelle Java et/ou de votre application.)


Est-il sage de toujours appeler SocketChannel.isConnected() avant d'essayer un SocketChannel.write() ...

En général, c'est une mauvaise idée d'appeler r.isXYZ() avant un appel utilisant la ressource (externe) r. Il y a une petite chance que l'état de la ressource change entre les deux appels. C'est une meilleure idée de faire l'action, d'attraper le IOException (ou quoi que ce soit) résultant de l'action manquée et de prendre les mesures correctives nécessaires.

Dans ce cas particulier, appeler isConnected() est inutile. La méthode est définie pour renvoyer truesi la socket a été connectée à un moment donné. Il ne vous dit pas si la connexion est toujours active. Le seul moyen de déterminer si la connexion est toujours active consiste à tenter de l'utiliser. par exemple. faire une lecture ou écrire.

96
Stephen C

Un tuyau cassé signifie simplement que la connexion a échoué. Il est raisonnable de supposer que cela est irrécupérable et d’effectuer ensuite les actions de nettoyage requises (fermeture des connexions, etc.). Je ne crois pas que cela se reproduirait tout simplement parce que la connexion n’était pas encore complète.

Si vous utilisez le mode non bloquant, la méthode SocketChannel.connect renverra false et vous devrez utiliser les méthodes isConnectionPending et finishConnect pour vous assurer que la connexion est établie. Je coderais généralement en fonction de l'espoir que les choses fonctionneraient, puis attraperais les exceptions pour détecter les échecs, plutôt que de compter sur des appels fréquents à "isConnected".

23
jsight

Un tuyau cassé signifie que vous avez écrit sur une connexion déjà fermée par l’autre extrémité.

isConnected() ne détecte pas cette condition. Seule une écriture le fait.

est-il sage de toujours appeler SocketChannel.isConnected () avant de tenter un SocketChannel.write ()

C'est inutile. Le socket lui-même est connecté. Vous l'avez connecté. Ce que peut ne pas être connecté est la connexion elle-même, et vous ne pouvez le déterminer qu'en essayant.

18
user207421

Vous devez supposer que le socket est fermé à l'autre bout. Enveloppez votre code avec un bloc catch try pour IOException.

Vous pouvez utiliser isConnected () pour déterminer si le SocketChannel est connecté ou non, mais cela pourrait changer avant la fin de votre appel write (). Essayez de l'appeler dans votre bloc catch pour voir si c'est en fait la raison pour laquelle vous obtenez l'exception IOException.

1
Sean A.O. Harney