Rubyでソケットタイムアウトを設定するにはどうすればよいですか?
-
04-07-2019 - |
質問
Rubyソケットでのブロック操作のタイムアウトをどのように設定しますか?
解決
私が見つけた解決策は、タイムアウトを使用することです。 ::タイムアウト:
require 'timeout'
...
begin
timeout(5) do
message, client_address = some_socket.recvfrom(1024)
end
rescue Timeout::Error
puts "Timed out!"
end
他のヒント
タイムアウトオブジェクトは良い解決策です。
これは非同期I / Oの例です(本質的に非ブロッキングであり、 アプリケーションのフロー。)
IO.select(read_array
[, write_array
[, error_array
[, timeout]]] ) => array or nil
同じ効果を得るために使用できます。
require 'socket'
strmSock1 = TCPSocket::new( "www.dn.se", 80 )
strmSock2 = TCPSocket::new( "www.svd.se", 80 )
# Block until one or more events are received
#result = select( [strmSock1, strmSock2, STDIN], nil, nil )
timeout=5
timeout=100
result = select( [strmSock1, strmSock2], nil, nil,timeout )
puts result.inspect
if result
for inp in result[0]
if inp == strmSock1 then
# data avail on strmSock1
puts "data avail on strmSock1"
elsif inp == strmSock2 then
# data avail on strmSock2
puts "data avail on strmSock2"
elsif inp == STDIN
# data avail on STDIN
puts "data avail on STDIN"
end
end
end
ノンブロッキングアプローチが進むべき道だと思います。
上記の記事を試してみたところ、まだハングする可能性がありました。
この記事非ブロッキングネットワークおよびjonkeの上記のアプローチは、私を正しい道に導きました。私のサーバーは最初の接続でブロックしていたので、少し低いレベルにする必要がありました。
ソケットrdocは、connect_nonblockに詳細を提供できます
def self.open(host, port, timeout=10)
addr = Socket.getaddrinfo(host, nil)
sock = Socket.new(Socket.const_get(addr[0][0]), Socket::SOCK_STREAM, 0)
begin
sock.connect_nonblock(Socket.pack_sockaddr_in(port, addr[0][3]))
rescue Errno::EINPROGRESS
resp = IO.select([sock],nil, nil, timeout.to_i)
if resp.nil?
raise Errno::ECONNREFUSED
end
begin
sock.connect_nonblock(Socket.pack_sockaddr_in(port, addr[0][3]))
rescue Errno::EISCONN
end
end
sock
end
良好なテストを取得します。単純なソケットサーバーを起動し、Ctrl-Zを押してバックグラウンドを実行します
IO.selectは、10秒以内に入力ストリームにデータが入ってくることを期待しています。そうでない場合、これは機能しない可能性があります。
これは、TCPSocketのopenメソッドの優れた代替品です。
所属していません StackOverflow