2009-11-27 11 views
32

Tengo un error Broken pipe (Errno::EPIPE) apareciendo y no entiendo qué es o cómo solucionarlo. el error completo es:Tubo roto (Errno :: EPIPE)

example.rb:19:in `write': Broken pipe (Errno::EPIPE) 
    from example.rb:19:in `print' 
    from example.rb:19 

línea 19 de mi código es:

vari.print("x=" + my_val + "&y=1&z=Add+Num\r\n") 

Respuesta

21

Esto significa que cualquiera que sea la impresión de conexión está dando salida a ya no está conectado. Es de suponer que el programa comenzó como entrada a algún otro programa:

% ruby_program | another_program 

Lo que pasa es que another_program ha salido en algún momento antes de la print en cuestión.

+0

en realidad, este código es todo para una solicitud http. ¿Eso solo significa que el servidor no está conectado en ese punto? esto parece estar sucediendo al azar. – sepiroth

+0

No sé mucho sobre ruby, pero EPIPE podría ser una desconexión de red. En Linux, esperaría que el error fuera ENETRESET, ECONNABORTED, ECONNRESET, ENOTCONN o ESHUTDOWN para esa condición. – wallyk

+1

@sepiroth: 'EPIPE' está _system_-defined; es el código de salida informado por una llamada al sistema que activó la señal 'SIGPIPE', que típicamente indica que el proceso en _reading_ end de _pipe_ ha salido (mientras que _writing_ end aún está intentando escribir en la tubería); adicionalmente, en un contexto _network_, [this] (https://www.gnu.org/software/libc/manual/html_mono/libc.html#Operation-Error-Signals) declara: "Otra causa de' SIGPIPE' es cuando intentas enviar a un _socket_ que no está conectado. Ver [Enviar datos] (https://www.gnu.org/software/libc/manual/html_mono/libc.html#Sending-Data) ". – mklement0

12

@wallyk tiene razón en el problema. Una solución consiste en capturar la señal con Signal.trap:

Signal.trap("PIPE", "EXIT") 
9

Aunque las trampas de señales funcionan, como se dijo tokland, se definen amplia aplicación y puede causar un comportamiento inesperado si desea manejar un tubo roto de alguna otra manera en otro lugar de tu aplicación

Sugeriría simplemente usar un rescate estándar ya que el error aún hereda de StandardError. Más información sobre este módulo de errores: http://ruby-doc.org/core-2.0.0/Errno.html

Ejemplo:

begin 
    vari.print("x=" + my_val + "&y=1&z=Add+Num\r\n") 
rescue Errno::EPIPE 
    puts "Connection broke!" 
end 

Editar: Es importante tener en cuenta (como @ mklement0 hace en los comentarios) que si estaban bien inicialmente su salida usando pone a algo esperando salida en STDOUT, la final pone en el código anterior se levantará otra excepción Errno :: EPIPE. Probablemente sea una mejor práctica usar STDERR.puts de todos modos.

begin 
    vari.print("x=" + my_val + "&y=1&z=Add+Num\r\n") 
rescue Errno::EPIPE 
    STDERR.puts "Connection broke!" 
end 
+0

+1 consejo razonable – tokland

+1

Suena sensato, pero en la práctica (Ruby 2.0.0) no he podido detectar este error; intente 'ruby -e 'begin; puts (1..10000) .map {| n | "línea # {n}"}; rescate Errno :: EPIPE; pone "No se puede hacer: # {$ !. mensaje}"; fin '| cabeza' - todavía se rompe; Incluso intentar rescatar 'Exception' no funciona. ¿Se me escapa algo? – mklement0

+2

@ mklement0 En realidad está rescatando la excepción, pero la excepción vuelve a plantearse en su instrucción de rescate porque está intentando escribir su cadena de excepción personalizada en STDOUT que todavía está siendo canalizada a la cabeza (y cuya tubería se ha roto ya) . Si ejecuta este 'ruby -e 'begin; puts (1..10000) .map {| n | "línea # {n}"}; rescate Errno :: EPIPE; STDERR.puts "No se puede hacer: # {$ !. mensaje}"; fin '| head' verás que rescata la excepción original Errno :: EPIPE. –

6

Lo siguiente se aplica principalmente a los scripts de Ruby diseñados para actuar como CLI; Las CLI generalmente solo necesitan finalizar silenciosamente con un código de salida específico al recibir SIGPIPE; para las secuencias de comandos que requieren el manejo caso por caso de SIGPIPE, considere donovan.lampa's helpful answer.

Para complementar wallyk's helpful answer y tokland's helpful answer:

Si desea que su script para exhibición del sistema por defecto comportamiento, como mayoría de las utilidades de Unix (por ejemplo, cat) hacer, utilice

Signal.trap("SIGPIPE", "SYSTEM_DEFAULT") 

al comienzo de su secuencia de comandos.

Ahora, cuando el script recibe la señal SIGPIPE (en sistemas tipo Unix), el comportamiento predeterminado del sistema:

  • silencio terminar su script
  • informe código de salida 141 (que se calcula como 128 (indicando la terminación por señal) + 13 (SIGPIPE 's número))

Por el contrario, Signal.trap("PIPE", "EXIT") informará el código de salida 0.

Tenga en cuenta que en una cáscara de contexto, el código de salida a menudo no es evidente en un comando como ruby examble.rb | head, porque el shell (por defecto) sólo reporta el código de salida del comando última.

En bash, puede examinar ${PIPESTATUS[@]} para ver los códigos de salida de todos los comandos en la tubería.