Я всего лишь инженер-механик (новичок в программировании), разрабатывающий веб-приложение для контроля выходной мощности солнечных систем клиентов.В настоящее время я пытаюсь реализовать сценарий, который используется моим приложением для открытия соединения с сокетом и запроса пользовательских преобразователей с использованием таймаутов и потоков.В настоящее время скрипт (который устанавливается через cron для запуска каждые 15 минут) очень тривиален и выглядит примерно так:
System.all.each do |system|
@sock = TCPSocket.open(system.ip,51101)
@query = "\x0A\x05\x03\x00\xB5\x00\x01\x94\x68\x0D"
@sock.write(@query)
@s = @sock.read(9)
# do stuff with @s
@sock.close
end
Одна из больших проблем, которую я хочу решить прежде всего: после захода солнца каждыйВ тот день, когда все клиентские инверторы выключаются в течение дня, и этот скрипт пытается выполнить свой первый socket.write / read, я полагаю, что он "зависает", потому что для того, чтобы он снова начал подключаться и запрашивать, я должен перезагрузить компьютер утром.Поэтому я хотел бы правильно реализовать тайм-ауты как на самом сокете, так и на socket.read, чтобы этого не произошло.Из исследования переполнения стека, которое я провел до сих пор, я подумал, что, возможно, мне следует сделать что-то вроде следующего, чтобы сделать то же самое, что и выше, но с сокетом, который истекает через 2 секунды:
@port = 51101
System.all.each do |system|
@sock = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
@sock_address = Socket.sockaddr_in(@port, system.ip)
begin
@sock.connect_nonblock(@sock_address)
@query = "\x0A\x05\x03\x00\xB5\x00\x01\x94\x68\x0D"
@sock.write(@query)
@s = @sock.read(9)
# do stuff with @s
@sock.close
rescue Errno::EINPROGRESS
if IO.select(nil, [@sock], nil, 2)
begin
@sock.connect_nonblock(@sock_address)
@query = "\x0A\x05\x03\x00\xB5\x00\x01\x94\x68\x0D"
@sock.write(@query)
@s = @sock.read(9)
# do stuff with @s
@sock.close
rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
# do something
end
end
end
end
Но есть ряд вещей, которые я не понимаю в этом коде.Во-первых, когда возникает Errno :: EINPROGRESS?Второй @sock.connect_nonblock(@sock_address)
появляется в строке 6, потому что этот код будет повторять соединение, если система уже пыталась «слишком долго», но не более 2 секунд?Кроме того, из того, что я прочитал, Errno :: EINPROGRESS, похоже, вещь для Windows.Каким будет эквивалент Mac OS?Или эти вопросы могут быть совершенно неуместны.Пожалуйста, дайте мне знать в любом случае, если я иду в правильном направлении.Или, если бы вы могли предоставить мне откомментированный фрагмент, демонстрирующий правильный способ сделать это.
Во-вторых, если сокет подключается очень хорошо, как я могу реализовать таймаут socket.read, чтобы он не заставлял все зависать (что, на мой взгляд, происходит на самом деле, когда инверторы выключаются)?Я продолжаю читать, что ruby timeout.rb не должен использоваться.Как я могу сделать это только попытаться прочитать в течение нескольких секунд, а затем закрыть сокет, если он зависает?Заранее большое спасибо.