47

特定のポートが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それまでに何も返されない場合は戻ります)、または特定のホストで特定のポートが開いているかどうかを確認するためのより良い方法はありますか?

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

4

8 に答える 8

54

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

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
于 2009-02-05T19:55:42.330 に答える
28

より 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
于 2012-01-26T12:08:23.997 に答える
28

All other existing answer are undesirable. Using Timeout is discouraged. Perhaps things depend on ruby version. At least since 2.0 one can simply use:

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

For older ruby the best method I could find is using non-blocking mode and then select. Described here:

于 2016-07-08T12:02:02.217 に答える
9

完全を期すために、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

于 2009-02-05T23:20:05.163 に答える
1

クリス・ライスの答えに対する私のわずかなバリエーション。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
于 2014-02-20T23:25:38.403 に答える