Я пытаюсь сделать тайм-аут сокетов в Ruby с помощью параметра сокета SO_RCVTIMEO, однако, похоже, это не имеет никакого эффекта ни в одной из последних операционных систем *nix.
Использование модуля Ruby Timeout не является вариантом, так как требует создания и присоединения потоков для каждого тайм-аута, что может стать дорогостоящим. В приложениях, требующих малых тайм-аутов сокетов и имеющих большое количество потоков, это существенно снижает производительность. Это было отмечено во многих местах, включая Stack Overflow.
Я прочитал отличный пост Майка Перхема на эту тему здесьи, пытаясь свести проблему к одному файлу исполняемого кода, создал простой пример 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
Установка этой опции сокета действительно работает для кого-нибудь?