Je besoin d'un moyen rapide de savoir si un port donné est ouvert avec Ruby. Je joue actuellement avec ceci:
require 'socket'
def is_port_open?(ip, port)
begin
TCPSocket.new(ip, port)
rescue Errno::ECONNREFUSED
return false
end
return true
end
Cela fonctionne bien si le port est ouvert, mais l'inconvénient de ceci est que, de temps en temps, il va simplement s'asseoir et attendre 10 à 20 secondes, puis éventuellement temps, jetant une exception ETIMEOUT
(si le port est fermé) . Ma question est donc:
Ce code peut-il être modifié pour attendre une seconde (et retour false
si nous ne récupérons rien d'ici à ce moment-là) ou y a-t-il un meilleur moyen de vérifier si un port donné est ouvert sur un hôte donné?
EDIT : appel de code Bash est également acceptable aussi longtemps que cela fonctionne dans la plate-forme multiplate-forme (par exemple, Mac OS X, * Nix et Cygwin), bien que je préfère Ruby = code.
Quelque chose comme ce qui suit pourrait fonctionner:
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
Plus Ruby syntaxe idiomatiques:
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
Toutes les autres réponses existantes sont indésirables. Utilisation Timeout
est découragé . Peut-être que les choses dépendent de la versionRuby. Au moins depuis 2.0 on peut simplement utiliser:
Socket.tcp("www.Ruby-lang.org", 10567, connect_timeout: 5) {}
Pour plus vieux Ruby la meilleure méthode que je pouvais trouver est d'utiliser le mode non bloquant, puis select
. Décrit ici:
J'ai récemment proposé cette solution, en utilisant la commande UNIX lsof
:
def port_open?(port)
!system("lsof -i:#{port}", out: '/dev/null')
end
Juste pour la complétude, la bash serait quelque chose comme ça:
$ netcat $Host $PORT -w 1 -q 0 </dev/null && do_something
-w 1
Spécifie un délai d'attente de 1 seconde et -q 0
dit que, lorsqu'il est connecté, fermez la connexion dès que stdin
donne EOF
(quel /dev/null
va faire tout de suite).
Bash a également ses propres services TCP/UDP intégrés, mais ils sont une option de compilation et je n'ai pas de bash compilé avec eux: P
Toutes les plateformes * Nix:
essayez la commande nc/netcat comme suit.
`nc -z -w #{timeout_in_seconds} -G #{timeout_in_seconds} #{Host} #{port}`
if $?.exitstatus == 0
#port is open
else
#refused, port is closed
end
Le drapeau -Z peut être utilisé pour indiquer à NC de signaler des ports ouverts plutôt que d'initier une connexion.
Le drapeau-w signifie le délai d'expiration de connexion et des lectures finales nettes
Le drapeau -g est le délai de connexion en secondes
Utilisez -n drapeau pour fonctionner avec l'adresse IP plutôt que le nom d'hôte.
Exemples:
# `nc -z -w 1 -G 1 google.com 80`
# `nc -z -w 1 -G 1 -n 123.234.1.18 80`
Ma légère variation de la réponse de Chris Rice. Poignée toujours sur une seule tentative, mais permet également de multiples tentatives jusqu'à ce que vous abandonniez.
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