#ruby #sockets
#ruby #сокеты
Вопрос:
У меня есть некоторый код, который я использую для получения данных из сетевого сокета. Это работает нормально, но я пробивался к нему методом проб и ошибок. Я смиренно признаю, что не до конца понимаю, как это работает, но мне бы очень хотелось. (Это был рабочий код грузовой формы, который я нашел)
Часть, которую я не понимаю, начинается с «ready = IO.select …» Я не совсем понимаю:
- Что делает IO.select (я пытался найти это, но еще больше запутался в ядре и чем-то еще)
- для чего нужен аргумент массива в IO.select
- что делает ready[0]
- общая идея чтения 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 байт данных, и если это не так, это определяет, что сокет мертв, верно??? Но тогда.. что, если в данный момент просто нет данных для чтения (которые могут появиться позже)? Как такого рода проверка может обеспечить хороший способ определить, разорвано ли соединение? .. Какую (большую?) часть этого я не получаю? Спасибо..