2009-11-27 17 views
32

Pojawił się błąd Broken pipe (Errno::EPIPE) i nie rozumiem, co to jest ani jak to naprawić. pełna błędu:Uszkodzona rura (Errno :: EPIPE)

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

linia 19 z mojego kodu jest:

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

Odpowiedz

21

Oznacza to, że niezależnie od druku połączenie jest wyprowadzanie do nie jest już podłączony. Prawdopodobnie program rozpoczął jako wejście do jakiegoś innego programu:

% ruby_program | another_program 

Co się stało, że another_program odszedł kiedyś przed print mowa.

+0

w rzeczywistości ten kod jest dla żądania http. czy to znaczy, że serwer nie jest podłączony w tym momencie? wydaje się, że dzieje się to przypadkowo. – sepiroth

+0

Nie wiem zbyt wiele na temat ruby, ale EPIPE może być rozłączeniem sieci. W Linuksie spodziewam się błędu: ENETRESET, ECONNABORTED, ECONNRESET, ENOTCONN lub ESH DOWNDOWN dla tego warunku. – wallyk

+1

@ semiroth: 'EPIPE' jest zdefiniowany przez _system_; jest to kod wyjścia zgłoszony przez wywołanie systemowe, które wyzwoliło sygnał 'SIGPIPE', co zwykle oznacza, że ​​proces na końcu _readinga _pipe_ został zakończony (podczas gdy _pisujący_ koniec nadal próbuje zapisać do potoku); dodatkowo, w kontekście _network_, [this] (https://www.gnu.org/software/libc/manual/html_mono/libc.html#Operation-Error-Signals) stwierdza: "Inną przyczyną' SIGPIPE' jest przy próbie wyprowadzenia na _socket_, który nie jest połączony. Patrz [Wysyłanie danych] (https://www.gnu.org/software/libc/manual/html_mono/libc.html#Sending-Data) ". – mklement0

12

@Wallyk jest tuż przy problemie. Jednym z rozwiązań jest przechwytywanie sygnału z Signal.trap:

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

Chociaż pułapki sygnałowe działają, jak tokland powiedział, są one zdefiniowane aplikację szeroki i może powodować nieoczekiwane zachowanie, jeśli chcesz obsługiwać złamaną fajkę w jakiś inny sposób gdzieś indziej w Twojej aplikacji.

Proponuję użyć standardowego ratunku, ponieważ błąd nadal dziedziczy po StandardError. Więcej informacji na temat tego modułu błędów: http://ruby-doc.org/core-2.0.0/Errno.html

Przykład:

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

Edit: Ważne jest, aby pamiętać (jak @ mklement0 robi w komentarzach), że jeśli były pierwotnie potokiem dane wyjściowe przy użyciu stawia na coś spodziewając się wyniku na STDOUT, końcowe umieszczenie w powyższym kodzie zwiększy kolejny wyjątek Errno :: EPIPE. Prawdopodobnie lepiej jest używać STDERR.puts.

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

+1 rozsądna porada – tokland

+1

Brzmi rozsądnie, ale w praktyce (Ruby 2.0.0) Nie byłem w stanie złapać tego błędu; spróbuj 'ruby--e '; puts (1..10000) .map {| n | "line # {n}"}; ratowanie Errno :: EPIPE; umieszcza "Nie można zrobić: # {$ !. wiadomość}"; koniec "| head' - wciąż pęka; Nawet próba ratowania 'Wyjątku' nie działa. Czy jest coś, czego mi brakuje? – mklement0

+2

@ mklement0 Naprawdę ratujesz wyjątek, ale wyjątek zostanie podniesiony ponownie w twoim ratowniczym oświadczeniu, ponieważ próbujesz napisać swój niestandardowy ciąg znaków wyjątku do STDOUT, który wciąż jest podłączony do głowicy (i którego rura w głowę została już uszkodzona) . Jeśli uruchomisz 'ruby -e ', zacznij; puts (1..10000) .map {| n | "line # {n}"}; ratowanie Errno :: EPIPE; STDERR.puts "Nie można zrobić: # {$ !. wiadomość}"; koniec "| head' zobaczysz, że naprawdę uratował oryginalny wyjątek Errno :: EPIPE. –

6

Ponizsze odnosi się przede wszystkim do skryptów Ruby zaprojektowane do działania jako CLIS; Zwykle po prostu CLI muszą zakończyć cicho z określonym kodem wyjścia po otrzymaniu SIGPIPE; w przypadku skryptów, które wymagają indywidualnej obsługi SIGPIPE, należy rozważyć donovan.lampa's helpful answer.

celu uzupełnienia wallyk's helpful answer i tokland's helpful answer:

Jeśli chcesz skrypt do eksponatu domyślnego systemu zachowanie, jak większości narzędzi uniksowych (np cat) zrobić, użyj

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

na początku skryptu.

Teraz, gdy skrypt odbiera sygnał SIGPIPE (w systemach uniksowych), domyślne zachowanie systemu będą:

  • cicho zakończyć skrypt
  • raport kod wyjścia 141 (co jest obliczany jako 128 (wskazujący na zakończenie przez sygnał) + 13 (SIGPIPE 's numer))

W przeciwieństwie do tego, Signal.trap("PIPE", "EXIT") wyświetli kod wyjścia 0.

Należy zauważyć, że w powłoki kontekście kod wyjścia często nie jest widoczne w poleceniu takich jak ruby examble.rb | head, ponieważ powłoka (domyślnie) informuje tylko kod opuścić ostatni dowództwa.

W bash można sprawdzić ${PIPESTATUS[@]}, aby wyświetlić kody wyjścia wszystkie polecenia w potoku.