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