Is there a ruby way to pass file descriptors to separate processes?
I'm thinking of interfacing with a C program, which uses the
SCM_RIGHTS cmsg over a unix-domain socket ... is this idiom
implemented in Ruby? How would I marshall an IO object into (and out
of) the integer file descriptor, or does this "just work"?
After a little investigation, this turned out to be easier than
I thought. The following code was tested on Mac OS X with ruby 1.8.5.
There are three files below, don't cut and paste the whole thing:
socketpair.rb # example with parent/child
server.rb # example with unrelated processes
client.rb
Socketpair.rb and client.rb both take a single argument, the name
of the data file to open.
Start server.rb before running client.rb.
If you try this on something other than Mac OS X ruby 1.8.5, let us
know how it works.
Gary Wright
$ cat socketpair.rb
# Scenario 1: parent and child related via fork
require 'socket'
read, write = UNIXSocket.pair
puts "parent end: #{read.inspect}, #{read.fileno}"
puts "child end: #{write.inspect}, #{write.fileno}"
pid = fork {
file = File.open(ARGV[0])
puts "child is sending: #{file.inspect}/#{file.fileno} connected
to #{ARGV[0]}"
write.send_io(file)
exit
}
thefile = read.recv_io
puts "parent received: #{thefile.inspect}/#{thefile.fileno}, contents:"
puts thefile.read
# end of scenario 1
$ cat server.rb
require 'socket'
serv = UNIXServer.new("/tmp/server")
p "server listening for connections: #{serv.inspect}"
client = serv.accept
p "received connection: #{client.inspect}"
clientfile = client.recv_io
puts "parent received fd: #{clientfile.fileno}, contents:"
puts clientfile.read
# end of server.rb
$ cat client.rb
require 'socket'
server = UNIXSocket.new("/tmp/server")
puts "connected to : #{server.inspect}"
fd = File.open(ARGV[0])
puts "child is sending fd: #{fd.fileno} connected to #{ARGV[0]}"
server.send_io(fd) # we are *not* sending the data!
exit