Broken Pipe (Errno::Epipe)

Broken pipe (Errno::EPIPE)

It means that whatever connection print is outputting to is no longer connected. Presumably the program began as input to some other program:

 % ruby_program | another_program

What's happened is that another_program has exited sometime before the print in question.

Errno::EPIPE: Broken pipe exception is raised

Not sure why this has taken so long to get answered. I suspect this is "fixed" in current versions of ruby as I was unable to replicate using simplified versions of your code, but for future reference, here's how I would have structured the code:

def test_my_pipes
rd, wr = IO.pipe
fork do
rd.close
sleep 5
wr.write "Hello world"
wr.close
end
wr.close # essential
puts "Waiting for sleepy fork"
puts rd.read
rd.close
end

Note that both inside and outside the fork block, we close both rd and wr. In actual fact, only the parent process wr.close is essential, but definitely better to close all the ends of the pipe when not needed.

If this code still breaks, would be interested to see what versions of ruby they break for.

Ruby Broken pipe @ io_write - STDOUT

Introduction

Firstly, an explanation can be found here.

Anyways, here's my thought...

When a pipe is used like this:

a | b

Both a and b are executed concurrently. b waits for standard input from a.

Speaking of Errno::EPIPE, The Linux man page of write says:

EPIPE fd is connected to a pipe or socket whose reading end is
closed. When this happens the writing process will also
receive a SIGPIPE signal. (Thus, the write return value is
seen only if the program catches, blocks or ignores this
signal.)

Talking about the problem in the question:
When the program whoami is run, it exits and no longer accepts standard inputs that ruby program hello.rb is sending - resulting in a broken pipe.

Here I wrote 2 ruby programs, named p.rb and q.rb to test that:

  • p.rb
#!/usr/bin/env ruby
print ?* * 100_000
  • q.rb
#!/usr/bin/ruby
exit! 0

Running:

bash[~] $ ruby p.rb | ruby q.rb

Traceback (most recent call last):
2: from p.rb:2:in `<main>'
1: from p.rb:2:in `print'
p.rb:2:in `write': Broken pipe @ io_write - <STDOUT> (Errno::EPIPE)

Let's change the code of q.rb a bit, so that it accepts inputs:

#!/usr/bin/ruby -w
STDIN.gets

Running:

bash[~] $ ruby p.rb | ruby q.rb

Right, it displays nothing actually. The reason is that q.rb now waits for standard inputs. Apparently, the waiting is what matters the most here. Now, p.rb will not crash with even with STDOUT.sync or STDOUT.flush when piped to this q.rb.

Another Example:

  • p.rb
STDOUT.sync = true
loop until print("\e[2K<<<#{Time.now.strftime('%H:%M:%S:%2N')}>>>\r")

[warning: the loop without sleep may bring up your CPU usage]

  • q.rb
sleep 3

Running:

bash[~] $ time ruby p.rb | q.rb
Traceback (most recent call last):
2: from p.rb:2:in `<main>'
1: from p.rb:2:in `print'
p.rb:2:in `write': Broken pipe @ io_write - <STDOUT> (Errno::EPIPE)

real 0m3.186s
user 0m0.282s
sys 0m0.083s

You see the program crashed after 3 seconds. It will crash after 5.1 seconds if q.rb had sleep 5. Similarly sleep 0 in q.rb will crash p.rb after 0.1 seconds. I guess the additional 0.1 seconds depends on the system because my system takes 0.1 seconds to load the ruby interpreter.

I wrote p.cr and q.cr Crystal programs to test. Crystal is compiled and doesn't take the long 0.1 seconds to load up.

The Crystal Programs:

  • p.cr
STDOUT.sync = true
loop do print("\e[2KHi!\r") end rescue exit
  • q.cr
sleep 3

I compiled them, and ran:

bash[~] $ time ./p | ./q

real 0m3.013s
user 0m0.007s
sys 0m0.019s

The binary ./p, in very close to 3 seconds, handles Unhandled exception: Error writing file: Broken pipe (Errno) and exits. Again, 0.01 seconds may be taken by the two crystal programs to execute and maybe the Kernel also takes a bit time to run the processes.

Also note that STDERR#print, STDERR#puts, STDERR#putc, STDERR#printf, STDERR#write, STDERR#syswrite doesn't raise Errno::EPIPE even if the output is in sync.

Conclusion

Pipe is arcane. Setting STDOUT#sync to true or using STDOUT#flush flushes all buffered data to the underlying operating system.

When running hello.rb | whoami, without sync, I can write 8191 bytes of data, and the program hello.rb doesn't crash. But with sync, writing 1 byte via pipe will crash hello.rb.

So when hello.rb synchronizes standard outputs with the piped program whoami, and whoami doesn't wait for hello.rb; hello.rb raises Errno::EPIPE because the pipe between these two programs is broken (correct me if I am lost here).

Errno::EPIPE: Broken pipe with Net::FTP

put: PORT 10,142,96,98,199,111

You are using FTP in active mode with the private IP address 10.142.96.199. With active mode the server must create a data connection to your host, while with passive mode (PASV command instead of PORT command) the client will connect to the server.

Since the server is not on the same private network as your host (otherwise you would not be able to connect from a remote system to it) it will not be able to connect to the private IP of 10.142.96.98 given in the PORT command, because private IP addresses can not be accessed from the internet. The server will probably realize this, send some error back and close the connection. Your FTP client will probably try to send another command (like QUIT or ABOR) but since the server has already closed the connection this send will result in EPIPE.

FileZilla works probably because it will use passive mode instead of active mode. To use passive mode with Net::FTP you have to set ftp.passive = true.

ERROR Errno::EPIPE: Broken pipe with Culerity

i believe that an upgrade of jruby to a version matching the patch level of ruby that we were running solved our issue, we had to install jruby from source to get the right one

Exception Errno::EPIPE in Passenger RequestHandler (Broken pipe)

It looks like the bug you're having was merged into Passenger master but not yet released. You can try it out by checking Passenger out from the following repository:

http://github.com/FooBarWidget/passenger/tree/master

Once you've checked it out, you want to run:

./bin/passenger-install-apache2-module

for Apache Passenger, or:

./bin/passenger-install-nginx-module

for Nginx Passenger. Since this particular issue was addressed, it should work for you.



Related Topics



Leave a reply



Submit