Установить тайм-аут сокета в Ruby с помощью параметра сокета SO_RCVTIMEO

Я пытаюсь сделать тайм-аут сокетов в 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

Установка этой опции сокета действительно работает для кого-нибудь?

19
задан Community 23 May 2017 в 12:25
поделиться