Blocking berkeley sockets normally used by Ruby has one downside: if connection with remote computer is not gracefully terminated, the recv() call will wait for hours. Normally, this can be fixed by specifying receive timeout for socket. I have tried following code with Ruby 1.9.3-p0 on both Windows 7 and Ubuntu 11.10. Unfortunately, it don’t work: recv() hangs forever :(. What i’m doing wrong?
# server.rb
require 'socket'
Socket.tcp_server_loop( 1234 ) { puts( "connected" ) }
# client.rb
require 'socket'
sock = Socket.new( :INET, :STREAM )
time = if RUBY_PLATFORM =~ /mingw/ then 1000 else [ 1, 0 ].pack( 'L*' ) end
sock.setsockopt( Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, time )
sock.connect( Socket.sockaddr_in( 1234, "127.0.0.1" ) )
sock.recv( 100 )
I’m not sure what you’re trying to do, but the server never writes anything. Also, because of the way you are using
tcp_server_loop, the socket never gets closed but goes out of scope, which means that it will only be closed on next garbage collection. Because you are listening for data that never comes on a socket that was never closed on the server end, that must have something to do with it. Try this for the server:As for the time, on Linux, I can only guess that it is a matter of padding. I think you are imagining the perfect sequential struct which doesn’t exist. You should only really use binary structs that have been returned from C functions. And if you know the option works in C/C++, you could write a simple extension that just defines one Ruby function that sets creates a socket, sets that option, and returns it. That is probably harder than it sounds, but is a reliable option.
EDIT:
You could use Ruby’s timeout library and create a timeout around the
recvcall. It would look like this now: