[英]Ruby - See if a port is open
我需要一種快速的方法來確定給定的端口是否已使用 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
異常(如果端口關閉)。 我的問題是:
是否可以將此代碼修改為僅等待一秒鍾(如果到那時我們一無所獲,則返回false
),或者是否有更好的方法來檢查給定主機上的給定端口是否打開?
編輯:調用 bash 代碼也是可以接受的,只要它跨平台工作(例如,Mac OS X、*nix 和 Cygwin),盡管我更喜歡 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
我對克里斯賴斯的回答略有不同。 仍然處理一次嘗試超時,但也允許多次重試,直到您放棄。
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
所有 *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 標志是以秒為單位的連接超時
使用 -n 標志來處理 IP 地址而不是主機名。
例子:
# `nc -z -w 1 -G 1 google.com 80`
# `nc -z -w 1 -G 1 -n 123.234.1.18 80`
我的解決方案來自已發布的解決方案。
require 'socket'
def is_port_open?(ip, port)
begin
s = Socket.tcp(ip, port, connect_timeout: 5)
s.close
return true
rescue => e
# possible exceptions:
# - Errno::ECONNREFUSED
# - Errno::EHOSTUNREACH
# - Errno::ETIMEDOUT
puts "#{e.class}: #{e.message}"
return false
end
end
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.