19

如何为 Ruby 套接字上的阻塞操作设置超时?

4

3 回答 3

16

我发现似乎可行的解决方案是使用Timeout::timeout

require 'timeout'
    ...
begin 
    timeout(5) do
        message, client_address = some_socket.recvfrom(1024)
    end
rescue Timeout::Error
    puts "Timed out!"
end
于 2008-10-23T21:47:45.763 回答
15

超时对象是一个很好的解决方案。

这是异步 I/O 的一个示例(本质上是非阻塞的,并且与应用程序的流程异步发生。)

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

可以用来获得相同的效果。

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
于 2008-10-24T07:34:20.337 回答
8

我认为非阻塞方法是要走的路。
我试过上面提到的文章,仍然可以让它挂起。
这篇文章非阻塞网络和上面的 jonke 方法让我走上了正确的道路。我的服务器在初始连接时被阻塞了,所以我需要它稍微低一点。
套接字 rdoc 可以在 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.

于 2010-05-07T19:46:16.673 回答