Ruby で SO_RCVTIMEO ソケット オプションを使用してソケットをタイムアウトさせようとしていますが、最近の *nix オペレーティング システムでは効果がないようです。
Ruby の Timeout モジュールを使用することはオプションではありません。これは、タイムアウトごとにスレッドを生成して結合する必要があり、コストが高くなる可能性があるためです。低いソケット タイムアウトを必要とし、スレッド数が多いアプリケーションでは、基本的にパフォーマンスが低下します。これは、 Stack Overflowを含む多くの場所で指摘されています。
この件に関する Mike Perham の優れた投稿を読みました。問題を実行可能なコードの 1 つのファイルに減らすために、リクエストを受信し、リクエストで送信された時間を待機し、その後、接続を閉じます。
クライアントはソケットを作成し、受信タイムアウトを 1 秒に設定してから、サーバーに接続します。クライアントは、5 秒後にセッションを閉じるようにサーバーに指示し、データを待ちます。
クライアントは 1 秒後にタイムアウトするはずですが、代わりに 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
このソケットオプションの設定は実際に誰にとっても機能しますか?