Rubin - Prüfen Sie, ob ein Port offen ist
-
21-08-2019 - |
Frage
Ich brauche einen schnellen Weg, um herauszufinden, ob ein gegebener Port Ruby geöffnet ist. Ich bin derzeit Hantieren mit diesem:
require 'socket'
def is_port_open?(ip, port)
begin
TCPSocket.new(ip, port)
rescue Errno::ECONNREFUSED
return false
end
return true
end
Es funktioniert großartig, wenn der Port offen ist, aber die Kehrseite der Medaille ist, dass gelegentlich es wird einfach nur sitzen und für 10-20 Sekunden warten und dann schließlich eine Auszeit, eine ETIMEOUT
Ausnahme werfen (wenn der Port geschlossen ist). Meine Frage ist also:
Dieser Code kann geändert werden, um nur eine Sekunde lang zu warten (und false
zurück, wenn wir nichts zurück bis dahin) oder gibt es eine bessere Art und Weise zu überprüfen, ob ein bestimmt Port auf einem bestimmten Host geöffnet ist?
Edit:. bash Code aufrufen akzeptabel ist auch, solange es Cross-Plattform (zB Mac OS X, * nix, und Cygwin) funktioniert, obwohl ich Code Ruby-bevorzugen
Lösung
So etwas wie die folgenden funktionieren könnte:
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
Andere Tipps
Weitere Ruby-idiomatische Syntax:
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
All andere bestehende Antwort ist unerwünscht. Timeout
Mit entmutigtem . Vielleicht hängen die Dinge auf Ruby-Version. Mindestens seit 2.0 kann man einfach nutzen:
Socket.tcp("www.ruby-lang.org", 10567, connect_timeout: 5) {}
Für älteren rubin die beste Methode, die ich finden konnte unter Verwendung von nicht-blockierenden Modus und dann select
. Hier beschrieben:
Ich kam vor kurzem mit dieser Lösung auf, die Verwendung des Befehls Unix lsof
machen:
def port_open?(port)
!system("lsof -i:#{port}", out: '/dev/null')
end
Nur der Vollständigkeit halber, wäre die Bash etwas wie folgt aus:
$ netcat $HOST $PORT -w 1 -q 0 </dev/null && do_something
-w 1
legt einen Timeout von 1 Sekunde und -q 0
sagt, dass, wenn verbunden, die Verbindung schließen, sobald stdin
EOF
gibt (die /dev/null
gerade tun wird entfernt).
Bash hat auch einen eigenen integrierten TCP / UDP-Dienste, aber sie sind eine Kompilierung-Option und ich habe keinen Bash kompiliert mit ihnen: P
Alle * nix-Plattformen:
versuchen nc / netcat Befehl wie folgt.
`nc -z -w #{timeout_in_seconds} -G #{timeout_in_seconds} #{host} #{port}`
if $?.exitstatus == 0
#port is open
else
#refused, port is closed
end
Die Option -z kann verwendet werden, nc zu sagen, offene Ports zu berichten, anstatt eine Verbindung zu initiieren.
Das Flag -w bedeutet Timeout für eine Verbindung herstellt und endgültigen Netto liest
-G-Flag ist die Verbindungszeit in Sekunden
Verwenden Sie -n mit IP-Adresse zu arbeiten, anstatt Hostnamen.
Beispiele:
# `nc -z -w 1 -G 1 google.com 80`
# `nc -z -w 1 -G 1 -n 123.234.1.18 80`
Meine leichte Variation zu Chris Rice Antwort. Noch Griffe an einem einzigen Versuch Timing, sondern ermöglicht auch mehrere Wiederholungen, bis Sie aufgeben.
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