$ irb
1.9.3-p448 :001 > require 'socket'
=> true
1.9.3-p448 :002 > TCPSocket.new('www.example.com', 111)
给出
Errno :: ETIMEDOUT:操作超时 - 连接(2)
问题:
TCPSocket.new
?答案 0 :(得分:13)
至少从2.0开始就可以使用:
Socket.tcp("www.ruby-lang.org", 10567, connect_timeout: 5) {}
对于旧版本@falstru,答案似乎是最好的。
答案 1 :(得分:10)
使用begin .. rescue Errno::ETIMEDOUT
来捕捉超时:
require 'socket'
begin
TCPSocket.new('www.example.com', 111)
rescue Errno::ETIMEDOUT
p 'timeout'
end
要捕获任何套接字例外,请改用SystemCallError
。
根据SystemCallError documentation:
SystemCallError是所有低级平台相关错误的基类。
当前平台上可用的错误是子类 SystemCallError并在Errno模块中定义。
TCPSocket.new
不直接支持超时。
使用Socket::connect_non_blocking
和IO::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)
答案 2 :(得分:2)
如果您希望避免使用the pitfalls of Timeout,但希望避免必须处理自己的*_nonblock
+ select
实施方式,则可以使用the tcp_timeout
gem
tcp_timeout gem monkey-patches TCPSocket#connect,#read和#write,以便它们使用非阻塞I / O并具有您可以启用的超时。
答案 3 :(得分:1)
您可以使用ruby的Timeout
模块进行超时:
reqiure 'socket'
reqiure 'timeout'
begin
Timeout.timeout(10) do
begin
TCPSocket.new('www.example.com', 111)
rescue Errno::ENETUNREACH
retry # or do something on network timeout
end
end
rescue Timeout::Error
puts "timed out"
# do something on timeout
end
你将在10秒后得到:
# timed out
# => nil