How do I set the socket timeout in Ruby?

前端 未结 3 1009
日久生厌
日久生厌 2020-12-08 11:24

How do you set the timeout for blocking operations on a Ruby socket?

相关标签:
3条回答
  • 2020-12-08 11:32

    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
    
    0 讨论(0)
  • 2020-12-08 11:33

    I think the non blocking approach is the way to go.
    I tried the mentioned above article and could still get it to hang.
    this article non blocking networking and the jonke's approach above got me on the right path. My server was blocking on the initial connect so I needed it to be a little lower level.
    the socket rdoc can give more details into the connect_nonblock

    def self.open(host, port, timeout=10)
     addr = Socket.getaddrinfo(host, nil)
     sock = Socket.new(Socket.const_get(addr[0][0]), Socket::SOCK_STREAM, 0)
    
     begin
      sock.connect_nonblock(Socket.pack_sockaddr_in(port, addr[0][3]))
     rescue Errno::EINPROGRESS
      resp = IO.select([sock],nil, nil, timeout.to_i)
      if resp.nil?
        raise Errno::ECONNREFUSED
      end
      begin
        sock.connect_nonblock(Socket.pack_sockaddr_in(port, addr[0][3]))
      rescue Errno::EISCONN
      end
     end
     sock
    end
    

    to get a good test. startup a simple socket server and then do a ctrl-z to background it

    the IO.select is expecting data to come in on the input stream within 10 seconds. this may not work if that is not the case.

    It should be a good replacement for the TCPSocket's open method.

    0 讨论(0)
  • 2020-12-08 11:52

    The timeout object is a good solution.

    This is an example of asynchronous I/O (non-blocking in nature and occurs asynchronously to the flow of the application.)

    IO.select(read_array
    [, write_array
    [, error_array
    [, timeout]]] ) => array or nil
    

    Can be used to get the same effect.

    require 'socket'
    
    strmSock1 = TCPSocket::new( "www.dn.se", 80 )
    strmSock2 = TCPSocket::new( "www.svd.se", 80 )
    # Block until one or more events are received
    #result = select( [strmSock1, strmSock2, STDIN], nil, nil )
    timeout=5
    
    timeout=100
    result = select( [strmSock1, strmSock2], nil, nil,timeout )
    puts result.inspect
    if result
    
      for inp in result[0]
        if inp == strmSock1 then
          # data avail on strmSock1
          puts "data avail on strmSock1"
        elsif inp == strmSock2 then
          # data avail on strmSock2
          puts "data avail on strmSock2"
        elsif inp == STDIN
          # data avail on STDIN
          puts "data avail on STDIN"
        end
      end
    end
    
    0 讨论(0)
提交回复
热议问题