Sean S. [email protected] wrote:
I’ve been playing around with an issue that is giving me a bit of a
headache and I’m hoping someone can point me in a more useful
direction…
On a standard startup, I have two variables:
$nCS = TCPServer.new(HOST, PORT)
$connected = Array.new
You’ll need:
$nCS.close_on_exec = false if $nCS.respond_to?(:close_on_exec=)
for compatibility with Ruby 2.0.0 in the future
Also, you probably don’t need $ global variables
As users connect to $nCS and login, their connection (and user data) is
passed to $connected.
I have a command that triggers a function “copyover” that is intended to
hot-reboot the server, hopefully maintaining the connections. While I’ve
tried writing the connections to a file and reloading them that way, the
closest I seem to have gotten is the following:
exec “./main.rb”, “–copyover”, *$nCS, *$connected
You can’t just pass an object over the command-line, the
file descriptor number is all you can pass:
exec “./main.rb”, “–copyover”, $nCS.fileno.to_s, *$connected
Then passing:
$nCS = ARGV[1]
You need to convert the file descriptor number back to an object:
$nCS = TCPServer.for_fd(ARGV[1].to_i)
$connected = ARGV[2]
I think you need to do something similar for $connected, too,
you can’t pass over a Ruby array, either, so maybe something
along these lines:
in the original, stringify a list of integer file descriptors:
(you’ll get something like “4,5,6,7,8”)
connected_args = $connected.map do |sock|
sock.close_on_exec = false if sock.respond_to?(:close_on_exec=)
sock.fileno.to_s
end.join(“,”)
exec “./main.rb”, “–copyover”, $nCS.fileno.to_s, connected_args
in the exec-ed version:
parse the stringified list of descriptors:
connected_args = ARGV[2]
connected = connected_args.split(/,/).map do |sockfd|
I’m assuming TCPSocket is the correct class based on your use of
TCPServer, but any subclass of IO will support for_fd.
TCPSocket.for_fd(sock_fd)
end
Unrelated to your original problem, you should also check out the
optparse or similar libraries for parsing command-line options. They
can even handle the split(/,/) part for you.
Since Exec replaces the process, it should maintain the files until the
process is destroyed, correct?
Yes. However, Ruby 2.0.0 will set close_on_exec=true by default,
so you need to set close_on_exec=false to future-proof your code.
However, this still tells me “ERROR: Caught error in Client Thread:
Socket is not connected”
Can anyone point me in the right direction on this? I’m stumped!
Hopefully I didn’t make any typos or mistakes in my examples :> But the
basic idea is you can’t pass Ruby objects over the command-line (nor can
you marshall IO objects to strings). Passing stringified file
descriptor numbers is required in your case.
You can also use UNIX sockets with send_io/recv_io, but you still
need to know the class you’re recv_io-ing.