web-dev-qa-db-ja.com

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例外がスローされることです(ポートが閉じている場合)。 。私の質問はこうして:

このコードを修正して1秒だけ待つようにして(その時点で何も返されない場合はfalseを返す)、特定のホストで特定のポートが開いているかどうかを確認するより良い方法はありますか?

編集:クロスプラットフォーム(Mac OS X、* nix、Cygwinなど)で動作する限り、bashコードの呼び出しは許容されますが、Ruby =コード。

43
Chris Bunch

次のようなものが機能する可能性があります。

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
53
joast

もっと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
29
hipertracker

他のすべての既存の答えは望ましくありません。 Timeoutの使用は 非推奨 です。おそらく物事はRubyバージョンに依存します。少なくとも2.0以降では、単純に次のように使用できます:

Socket.tcp("www.Ruby-lang.org", 10567, connect_timeout: 5) {}

古いRubyの場合、私が見つけた最良の方法は、非ブロッキングモードを使用してからselectを使用することです。ここで説明します:

17
akostadinov

私は最近、UNIXのlsofコマンドを使用して、このソリューションを思いつきました。

def port_open?(port)
  !system("lsof -i:#{port}", out: '/dev/null')
end
13
Tobias Cohen

完全を期すために、Bashは次のようになります。

$ netcat $Host $PORT -w 1 -q 0 </dev/null && do_something

-w 1は1秒のタイムアウトを指定し、-q 0は、接続時にstdinEOF(これは/dev/nullはすぐに実行されます)。

Bashには独自のTCP/UDPサービスも組み込まれていますが、これらはコンパイル時のオプションであり、Bashをコンパイルしていません:P

10
porges

すべての* 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フラグは、秒単位の接続タイムアウトです

ホスト名ではなくIPアドレスを処理するには、-nフラグを使用します。

例:

# `nc -z -w 1 -G 1 google.com 80`
# `nc -z -w 1 -G 1 -n 123.234.1.18 80`
2

クリス・ライスの答えに対する私のわずかな変化。それでも、1回の試行でタイムアウトを処理しますが、あきらめるまで複数回再試行することもできます。

    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
1
Manther