如何定义Ruby TCPSocket超时?

ohh*_*hho 11 ruby sockets

$ irb
1.9.3-p448 :001 > require 'socket'
 => true 
1.9.3-p448 :002 > TCPSocket.new('www.example.com', 111)
Run Code Online (Sandbox Code Playgroud)

Errno :: ETIMEDOUT:操作超时 - 连接(2)

问题:

  • 如何定义超时值TCPSocket.new
  • 如何正确捕获超时(或一般来说,套接字)异常?

ako*_*nov 13

至少自2.0以来,人们可以简单地使用:

Socket.tcp("www.ruby-lang.org", 10567, connect_timeout: 5) {}
Run Code Online (Sandbox Code Playgroud)

对于旧版本@falstru,答案似乎是最好的.


fal*_*tru 10

使用begin .. rescue Errno::ETIMEDOUT捕捉超时:

require 'socket'

begin
  TCPSocket.new('www.example.com', 111)
rescue Errno::ETIMEDOUT
  p 'timeout'
end
Run Code Online (Sandbox Code Playgroud)

要捕获任何套接字异常,请SystemCallError改用.

根据SystemCallError文档:

SystemCallError是所有低级平台相关错误的基类.

当前平台上可用的错误是SystemCallError的子类,并在Errno模块中定义.


TCPSocket.new 不直接支持超时.

使用Socket::connect_non_blockingIO::select设置超时.

require 'socket'

def connect(host, port, timeout = 5)

  # Convert the passed host into structures the non-blocking calls
  # can deal with
  addr = Socket.getaddrinfo(host, nil)
  sockaddr = Socket.pack_sockaddr_in(port, addr[0][4])

  Socket.new(Socket.const_get(addr[0][0]), Socket::SOCK_STREAM, 0).tap do |socket|
    socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)

    begin
      # Initiate the socket connection in the background. If it doesn't fail 
      # immediatelyit will raise an IO::WaitWritable (Errno::EINPROGRESS) 
      # indicating the connection is in progress.
      socket.connect_nonblock(sockaddr)

    rescue IO::WaitWritable
      # IO.select will block until the socket is writable or the timeout
      # is exceeded - whichever comes first.
      if IO.select(nil, [socket], nil, timeout)
        begin
          # Verify there is now a good connection
          socket.connect_nonblock(sockaddr)
        rescue Errno::EISCONN
          # Good news everybody, the socket is connected!
        rescue
          # An unexpected exception was raised - the connection is no good.
          socket.close
          raise
        end
      else
        # IO.select returns nil when the socket is not ready before timeout 
        # seconds have elapsed
        socket.close
        raise "Connection timeout"
      end
    end
  end
end

connect('www.example.com', 111, 2)
Run Code Online (Sandbox Code Playgroud)

上面的代码来自" 在Ruby中设置套接字连接超时 ".