[英]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.