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 =コード。
次のようなものが機能する可能性があります。
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
もっと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
他のすべての既存の答えは望ましくありません。 Timeout
の使用は 非推奨 です。おそらく物事はRubyバージョンに依存します。少なくとも2.0以降では、単純に次のように使用できます:
Socket.tcp("www.Ruby-lang.org", 10567, connect_timeout: 5) {}
古いRubyの場合、私が見つけた最良の方法は、非ブロッキングモードを使用してからselect
を使用することです。ここで説明します:
私は最近、UNIXのlsof
コマンドを使用して、このソリューションを思いつきました。
def port_open?(port)
!system("lsof -i:#{port}", out: '/dev/null')
end
完全を期すために、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
すべての* 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`
クリス・ライスの答えに対する私のわずかな変化。それでも、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