Reputation: 3665
I am trying to do some communication between my ruby process and Python process; and I want to use UNIX socket.
Objective: ruby process "fork and exec" the Python process. In ruby process, create a UNIX socket pair, and pass it to Python.
Ruby code (p.rb):
require 'socket'
r_socket, p_socket = Socket.pair(:UNIX, :DGRAM, 0)
# I was hoping this file descriptor would be available in the child process
pid = Process.spawn('python', 'p.py', p_socket.fileno.to_s)
Process.waitpid(pid)
Python code (p.py):
import sys
import os
import socket
# get the file descriptor from command line
p_fd = int(sys.argv[1])
socket.fromfd(p_fd, socket.AF_UNIX, socket.SOCK_DGRAM)
# f_socket = os.fdopen(p_fd)
# os.write(p_fd, 'h')
command line:
ruby p.rb
Result:
OSError: [Errno 9] Bad file descriptor
I was hoping that the ruby process will pass the file descriptor to the python process, so that these two could send data using these socket.
So, my question:
1) Is it possible to pass open file descriptor between ruby and python process as above?
2) If we can pass around file descriptor between two processes, then what's wrong in my code.
Upvotes: 2
Views: 2347
Reputation: 34328
You were close, but Ruby spawn
closes any file descriptors > 2 by default, unless you pass :close_others => false
as argument. See the documentation:
http://apidock.com/ruby/Kernel/spawn
Working example:
require 'socket'
r_socket, p_socket = Socket.pair(:UNIX, :DGRAM, 0)
pid = Process.spawn('python', 'p.py', p_socket.fileno.to_s,
{ :close_others => false })
# Close the python end (we're not using it on the Ruby side)
p_socket.close
# Wait for some data
puts r_socket.gets
# Wait for finish
Process.waitpid(pid)
Python:
import sys
import socket
p_fd = int(sys.argv[1])
p_socket = socket.fromfd(p_fd, socket.AF_UNIX, socket.SOCK_DGRAM)
p_socket.send("Hello world\n")
Test:
> ruby p.rb
Hello world
Upvotes: 5