Понимание ввода-вывода.выбор при чтении сокета в Ruby

#ruby #sockets

#ruby #сокеты

Вопрос:

У меня есть некоторый код, который я использую для получения данных из сетевого сокета. Это работает нормально, но я пробивался к нему методом проб и ошибок. Я смиренно признаю, что не до конца понимаю, как это работает, но мне бы очень хотелось. (Это был рабочий код грузовой формы, который я нашел)

Часть, которую я не понимаю, начинается с «ready = IO.select …» Я не совсем понимаю:

  1. Что делает IO.select (я пытался найти это, но еще больше запутался в ядре и чем-то еще)
  2. для чего нужен аргумент массива в IO.select
  3. что делает ready[0]
  4. общая идея чтения 1024 байт? за раз

Вот код:

 @mysocket = TCPSocket.new('192.168.1.1', 9761)

th = Thread.new do
    while true
        ready = IO.select([@mysocket])
        readable = ready[0]

        readable.each do |socket|
            if socket == @mysocket
                buf = @mysocket.recv_nonblock(1024)
                if buf.length == 0
                    puts "The server connection is dead. Exiting."
                    exit
                else
                    puts "Received a message"
                end
            end
        end

    end
end
  

Заранее спасибо за то, что помогли мне «научиться ловить рыбу». Я ненавижу, когда в моем коде есть фрагменты, которые я не до конца понимаю — это просто работает по совпадению.

Комментарии:

1. Но почему вы используете новый поток? Каковы плюсы и минусы этого?

2. Я запустил пример, поместив кучу puts внутри и не могу понять, почему программа никогда не входит в while true цикл (или, может быть, puts вывод внутри цикла никогда не доходит до консоли?)

Ответ №1:

1) IO.select принимает набор сокетов и ждет, пока не станет возможным читать или записывать с их помощью (или если произойдет ошибка). Он возвращает событие сокетов, с которым произошло.

2) массив содержит сокеты, которые проверяются на наличие событий. В вашем случае вы указываете только сокеты для чтения.

3) IO.select возвращает массив массивов сокетов. Элемент 0 содержит сокеты, из которых вы можете читать, элемент 1 — сокеты, в которые вы можете записывать, и элемент 2 — сокеты с ошибками.

После получения списка сокетов вы можете прочитать данные.

4) да, recv_nonblock аргументом является размер в байтах. Обратите внимание, что размер фактически считываемых данных может быть меньше 1024, в этом случае вам может потребоваться повторить select (если для вас важны фактические данные).

Комментарии:

1. Таким образом, в основном это не использование select с аргументом timeout для определения того, является ли сокет активным, но он использует #recv для проверки того, возможно ли получить около 1024 байт данных, и если это не так, это определяет, что сокет мертв, верно??? Но тогда.. что, если в данный момент просто нет данных для чтения (которые могут появиться позже)? Как такого рода проверка может обеспечить хороший способ определить, разорвано ли соединение? .. Какую (большую?) часть этого я не получаю? Спасибо..