【发布时间】:2012-04-08 20:35:39
【问题描述】:
我正在尝试通过 SO_RCVTIMEO 套接字选项在 Ruby 中使套接字超时,但它似乎对任何最近的 *nix 操作系统都没有影响。
使用 Ruby 的 Timeout 模块不是一种选择,因为它需要为每个超时生成和加入线程,这可能会变得很昂贵。在需要低套接字超时且具有大量线程的应用程序中,它实际上会降低性能。许多地方都注意到了这一点,包括Stack Overflow。
我已经阅读了 Mike Perham 关于主题 here 的出色帖子,为了将问题减少到一个可运行代码文件,我创建了一个简单的 TCP 服务器示例,它将接收请求,等待一段时间在请求中发送,然后关闭连接。
客户端创建一个套接字,设置接收超时为1秒,然后连接到服务器。客户端告诉服务器在 5 秒后关闭会话,然后等待数据。
客户端应该在一秒后超时,但在 5 秒后成功关闭连接。
#!/usr/bin/env ruby
require 'socket'
def timeout
sock = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
# Timeout set to 1 second
timeval = [1, 0].pack("l_2")
sock.setsockopt Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, timeval
# Connect and tell the server to wait 5 seconds
sock.connect(Socket.pack_sockaddr_in(1234, '127.0.0.1'))
sock.write("5\n")
# Wait for data to be sent back
begin
result = sock.recvfrom(1024)
puts "session closed"
rescue Errno::EAGAIN
puts "timed out!"
end
end
Thread.new do
server = TCPServer.new(nil, 1234)
while (session = server.accept)
request = session.gets
sleep request.to_i
session.close
end
end
timeout
我也尝试使用 TCPSocket(自动连接)做同样的事情,并且在 redis 和其他项目中看到了类似的代码。
此外,我可以通过调用getsockopt 来验证该选项是否已设置,如下所示:
sock.getsockopt(Socket::SOL_SOCKET, Socket::SO_RCVTIMEO).inspect
设置这个套接字选项真的对任何人都有效吗?
【问题讨论】:
-
这种问题之前已经发过,看来最好的答案是在
recv调用周围使用Ruby的timeout库。 -
不,使用超时库会产生线程,因此每次超时都需要创建和销毁一个线程,这可能会变得非常昂贵。我将更新我的答案以反映它效率不高。
-
七年后,我们也了解到,它不仅效率低,而且危险。
标签: ruby sockets io timeout tcp-ip