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

War es hilfreich?

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
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top