Set Socket Timeout in Ruby Via So_Rcvtimeo Socket Option

Set socket timeout in Ruby via SO_RCVTIMEO socket option

You can do this efficiently using select from Ruby's IO class.

IO::select takes 4 parameters. The first three are arrays of sockets to monitor and the last one is a timeout (specified in seconds).

The way select works is that it makes lists of IO objects ready for a given operation by blocking until at least one of them is ready to either be read from, written to, or wants to raise an error.

The first three arguments therefore, correspond to the different types of states to monitor.

  • Ready for reading
  • Ready for writing
  • Has pending exception

The fourth is the timeout you want to set (if any). We are going to take advantage of this parameter.

Select returns an array that contains arrays of IO objects (sockets in this case) which are deemed ready by the operating system for the particular action being monitored.

So the return value of select will look like this:

[
[sockets ready for reading],
[sockets ready for writing],
[sockets raising errors]
]

However, select returns nil if the optional timeout value is given and no IO object is ready within timeout seconds.

Therefore, if you want to do performant IO timeouts in Ruby and avoid having to use the Timeout module, you can do the following:

Let's build an example where we wait timeout seconds for a read on socket:

ready = IO.select([socket], nil, nil, timeout)

if ready
# do the read
else
# raise something that indicates a timeout
end

This has the benefit of not spinning up a new thread for each timeout (as in the Timeout module) and will make multi-threaded applications with many timeouts much faster in Ruby.

How do I set the socket timeout in Ruby?

The solution I found which appears to work is to use Timeout::timeout:

require 'timeout'
...
begin
timeout(5) do
message, client_address = some_socket.recvfrom(1024)
end
rescue Timeout::Error
puts "Timed out!"
end

timeout for blocking TCP socket not working

SO_RCVTIMEO is no supported in a blocking socket.

If a blocking receive call times out, the connection is in an
indeterminate state
and should be closed. If the socket is created
using the WSASocket function, then the dwFlags parameter must have the
WSA_FLAG_OVERLAPPED attribute set for the timeout to function
properly. Otherwise the timeout never takes effect.

Using the WSASocket with WSA_FLAG_OVERLAPPED. Or socket()(default for WSA_FLAG_OVERLAPPED mode)

ruby 2.5: set timeout on tcp socket's read

Yes, IO::select, using recvfrom instead of gets (which might wait a while for a newline).

Socket C - setsockopt timeout do some things before closing

I have found a method :
The socket do the recv() before closing, so I check if the socket recive "" and I can send my message. The socket closing be himself after that.

What's the correct way to check if a host-alive and handle timeouts efficiently?

We make extensive use of Net::SSH in one of our systems, and ran into timeout issues.

Probably the biggest fix was to implement use of the select method, to set a low-level timeout, and not try to use the Timeout class, which is thread based.

"How do I set the socket timeout in Ruby?" and "Set socket timeout in Ruby via SO_RCVTIMEO socket option" have code to investigate for that. Also, one of those links to "Socket Timeouts in Ruby" which has useful code, however be aware that it was written for Ruby 1.8.6.

The version of Ruby can make a difference too. Pre-1.9 the threading wasn't capable of stopping a blocking IP session so the code would hang until the socket timed out, then the Timeout would fire. Both the above questions go over that.



Related Topics



Leave a reply



Submit