2009-07-25 23 views
61

Para algunas de mis conexiones Java NIO, cuando tengo una llamada SocketChannel.write(ByteBuffer), arroja un IOException: "Tubo roto".Java NIO: ¿Qué significa IOException: Broken pipe?

¿Qué causa una "tubería rota" y, lo que es más importante, ¿es posible recuperarse de ese estado? Si no se puede recuperar, parece que esto sería una buena señal de que ha ocurrido un problema irreversible y que simplemente debería cerrar esta conexión de socket. ¿Es eso una suposición razonable? ¿Hay alguna vez en que ocurra esto IOException mientras la conexión de socket todavía se está conectando correctamente en primer lugar (en lugar de una conexión que funciona que falló en algún momento)?

En una nota lateral, es prudente llamar siempre a SocketChannel.isConnected() antes de intentar una SocketChannel.write(), y si es así, ¿puedo suponer que la conexión está "roto" y debe ser cerrada si tanto SocketChannel.isConnected() y SocketChannel.isConnectionPending() son tanto false?

Gracias!

Respuesta

18

Tubo roto simplemente significa que la conexión ha fallado. Es razonable suponer que esto es irrecuperable, y luego realizar cualquier acción de limpieza requerida (conexiones de cierre, etc.). No creo que puedas ver esto simplemente debido a que la conexión aún no está completa.

Si está utilizando el modo sin bloqueo, el método SocketChannel.connect devolverá falso, y deberá usar los métodos isConnectionPending y finishConnect para asegurarse de que la conexión se haya completado. En general, codifico en función de la expectativa de que las cosas funcionen, y luego capturo excepciones para detectar fallas, en lugar de depender de las llamadas frecuentes a "isConnected".

+0

No se puede obtener una tubería rota sin antes haber tenido una tubería. No puede obtener una conexión fallida sin haber tenido previamente una conexión. El último párrafo de esta respuesta es correcto pero irrelevante. – EJP

1

Debe asumir que el socket estaba cerrado en el otro extremo. Envuelva su código con un bloque try catch para IOException.

Puede usar isConnected() para determinar si el SocketChannel está conectado o no, pero podría cambiar antes de que finalice su invocación de write(). Intenta llamarlo en tu bloque catch para ver si de hecho es por eso que recibes la IOException.

+4

en dicha excepción, isConnected() devuelve verdadero sin importar qué. Léelo como "socket se conectó en algún momento en el pasado" – kellogs

+3

El párrafo final de esta respuesta es completamente incorrecto. isConnected() no detecta esta condición. – EJP

73

¿Qué causa una "tubería rota" y, lo que es más importante, ¿es posible recuperarse de ese estado?

Es causado por algo que hace que la conexión se cierre. (No es su aplicación la que cerró la conexión: eso hubiera resultado en una excepción diferente)

No es posible recuperar la conexión. Necesitas abrir uno nuevo.

Si no se puede recuperar, parece que esto sería una buena señal de que se ha producido un problema irreversible y que simplemente debería cerrar esta conexión de socket. ¿Es eso una suposición razonable?

Sí. Una vez que haya recibido esa excepción, el socket no funcionará nunca más. Cerrarlo es lo único sensato que hay que hacer.

¿Hay algún momento en que se produciría este IOException mientras que la conexión de socket todavía se está conectado correctamente en el primer lugar (en lugar de una conexión de trabajo que ha fallado en algún momento)?

No. (O al menos, no sin subvertir el comportamiento adecuado de la pila de red OS'es, la JVM y/o su aplicación.)


¿Es prudente siempre llame SocketChannel.isConnected() antes de intentar una SocketChannel.write() ...

En general, es una mala idea llamar r.isXYZ() antes de que algunos de llamadas que utiliza el recurso (externo) r. Hay una pequeña posibilidad de que el estado del recurso cambie entre las dos llamadas. Es una mejor idea hacer la acción, tomar el IOException (o lo que sea) que resulte de la acción fallida y tomar las medidas correctivas necesarias.

En este caso particular, llamar al isConnected() no tiene sentido. El método se define para devolver truesi el socket se conectó en algún punto en el pasado. No te dice si la conexión aún está activa. La única forma de determinar si la conexión está viva es intentar usarla; p.ej. hacer una lectura o escribir

15

Pipa rota significa que usted escribió en una conexión que ya está cerrada por el otro extremo.

isConnected() no detecta esta condición. Solo una escritura lo hace.

es prudente siempre llame SocketChannel.isConnected() antes de intentar una SocketChannel.write()

No tiene sentido. El socket en sí es conectado. Lo conectaste Lo que puede no estar conectado es la conexión en sí, y solo puede determinarlo intentándolo.

Cuestiones relacionadas