Ruby - Посмотрите, открыт ли порт
Мне нужен быстрый способ узнать, открыт ли данный порт Ruby. Я в настоящее время занимаюсь этим:
require 'socket'
def is_port_open?(ip, port)
begin
TCPSocket.new(ip, port)
rescue Errno::ECONNREFUSED
return false
end
return true
end
Он отлично работает, если порт открыт, но недостатком этого является то, что иногда он просто сидит и ждет 10-20 секунд, а затем, в конце концов, отключается, бросая исключение ETIMEOUT
(если порт закрыт), Мой вопрос таков:
Можно ли изменить этот код, чтобы подождать только секунду (и вернуть false
, если мы ничего не получим к тому времени), или есть лучший способ проверить, открыт ли данный порт на данном хосте?
Изменить: Вызов bash кода допустим также, если он работает кросс-платформенным (например, Mac OS X, * nix и Cygwin), хотя я предпочитаю код Ruby.
Ответы
Ответ 1
Возможно, что-то вроде следующего:
require 'socket'
require 'timeout'
def is_port_open?(ip, port)
begin
Timeout::timeout(1) do
begin
s = TCPSocket.new(ip, port)
s.close
return true
rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
return false
end
end
rescue Timeout::Error
end
return false
end
Ответ 2
Подробнее Идиоматический синтаксис Ruby:
require 'socket'
require 'timeout'
def port_open?(ip, port, seconds=1)
Timeout::timeout(seconds) do
begin
TCPSocket.new(ip, port).close
true
rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
false
end
end
rescue Timeout::Error
false
end
Ответ 3
Просто для полноты, Bash будет примерно таким:
$ netcat $HOST $PORT -w 1 -q 0 </dev/null && do_something
-w 1
указывает тайм-аут 1 секунды, а -q 0
говорит, что при подключении закройте соединение, как только stdin
даст EOF
(который /dev/null
будет делать сразу).
Bash также имеет свои собственные встроенные службы TCP/UDP, но они являются параметрами времени компиляции, и у меня нет скомпилированных с ними Bash: P
Ответ 4
Недавно я придумал это решение, используя команду unix lsof
:
def port_open?(port)
!system("lsof -i:#{port}", out: '/dev/null')
end
Ответ 5
Все остальные существующие ответы нежелательны. Использование Timeout
обескуражено. Возможно, все зависит от версии ruby. По крайней мере с 2.0 можно просто использовать:
Socket.tcp("www.ruby-lang.org", 10567, connect_timeout: 5) {}
Для старого ruby лучший метод, который я мог найти, - это использовать неблокирующий режим, а затем select
. Описан здесь:
Ответ 6
Мое небольшое отклонение от Криса Райса. По-прежнему обрабатывает тайм-аут при одной попытке, но также допускает несколько попыток, пока вы не сдаетесь.
def is_port_open?(host, port, timeout, sleep_period)
begin
Timeout::timeout(timeout) do
begin
s = TCPSocket.new(host, port)
s.close
return true
rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
sleep(sleep_period)
retry
end
end
rescue Timeout::Error
return false
end
end
Ответ 7
Все платформы * nix:
Попробуйте выполнить команду nc/netcat, как показано ниже.
`nc -z -w #{timeout_in_seconds} -G #{timeout_in_seconds} #{host} #{port}`
if $?.exitstatus == 0
#port is open
else
#refused, port is closed
end
Флаг -z может использоваться, чтобы сообщить nc сообщать о открытых портах, а не инициировать соединение.
Флаг -w означает "Тайм-аут" для соединений и окончательные чистые чтения
Флаг -G - это время ожидания соединения в секундах
Использовать флаг -n для работы с IP-адресом, а не с именем хоста.
Примеры:
# `nc -z -w 1 -G 1 google.com 80`
# `nc -z -w 1 -G 1 -n 123.234.1.18 80`