2012-02-22 70 views
1

阻止Ruby常用的berkeley套接字有一個缺點:如果與遠程計算機的連接沒有正常結束,recv()調用將等待幾個小時。通常,可以通過爲套接字指定接收超時來解決此問題。我在Windows 7和Ubuntu 11.10上都嘗試了下面的代碼和Ruby 1.9.3-p0。不幸的是,它不工作:?recv()掛起永遠:(我在做什麼錯如何正確使用Ruby套接字的接收超時?

# 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) 

回答

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") 
+0

我想讓'recv()'返回,如果遠程沒有響應。我的服務器不會故意模擬連接沒有正常終止的情況。我知道'超時'技巧,但我更有興趣研究'recv()'行爲。 – grigoryvp 2012-02-22 16:40:38

+1

好的。我不知道使用Ruby的低級別Berkeley套接字。 – Linuxios 2012-02-23 01:04:32