如何正确使用Ruby套接字的接收超时?

时间:2012-02-22 14:19:58

标签: ruby sockets

阻止Ruby通常使用的berkeley套接字有一个缺点:如果没有正常终止与远程计算机的连接,recv()调用将等待数小时。通常,可以通过为socket指定 receive timeout 来解决此问题。我尝试在Windows 7和Ubuntu 11.10上使用Ruby 1.9.3-p0代码。不幸的是,它不起作用:recv()永远挂起:(。我做错了什么?

# server.rb
require 'socket'
Socket.tcp_server_loop( 1234 ) { puts( "connected" ) }

# client.rb
require 'socket'
sock = Socket.new( :INET, :STREAM )
time = if RUBY_PLATFORM =~ /mingw/ then 1000 else [ 1, 0 ].pack( 'L*' ) end
sock.setsockopt( Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, time )
sock.connect( Socket.sockaddr_in( 1234, "127.0.0.1" ) )
sock.recv( 100 )

1 个答案:

答案 0 :(得分:2)

我不确定你要做什么,但服务器从不写任何东西。此外,由于您使用tcp_server_loop的方式,套接字永远不会被关闭但超出范围,这意味着它只会在下一次垃圾回收时关闭。因为您正在侦听从未在服务器端从未关闭的套接字上发送的数据,所以这必须与它有关。试试服务器:

Socket.tcp_server_loop(1234) do |sock, clientinfo|
  puts "Connection!"
  begin
    sock.puts "Welcome to Wonderland"
  ensure
    sock.close
  end
end

至于时间,在Linux上,我只能猜测它是一个填充问题。我想你正在想象一个不存在的完美顺序结构。您应该只使用从C函数返回的二进制结构。如果您知道该选项适用于C / C ++,您可以编写一个简单的扩展,它只定义一个Ruby函数,集合创建一个套接字,设置该选项并返回它。这可能比听起来更难,但是可靠的选择。

编辑:

您可以使用Ruby的超时库并在recv调用周围创建超时。它现在看起来像这样:

require 'socket'
require 'timeout'
sock = Socket.new( :INET, :STREAM )
time = if RUBY_PLATFORM =~ /mingw/ then 1000 else [ 1, 0 ].pack( 'L*' ) end
sock.setsockopt( Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, time )
sock.connect( Socket.sockaddr_in( 1234, "127.0.0.1" ) )
(Timeout.timeout(100) {sock.recv( 100 )}) rescue puts("Recv timed out")