Ruby - 查看端口是否打开
-
21-08-2019 - |
题
我需要一种快速方法来查明给定端口是否已使用 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
其他提示
更多红宝石惯用语法:
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) {}
对于较旧的红宝石,我能找到的最好方法是使用非阻塞模式,然后 select
. 。此处描述:
我最近想出了这个解决方案,使得使用UNIX lsof
命令:
def port_open?(port)
!system("lsof -i:#{port}", out: '/dev/null')
end
只是为了保持完整性,猛砸会是这样的:
$ netcat $HOST $PORT -w 1 -q 0 </dev/null && do_something
-w 1
指定1秒的超时,并-q 0
说,当连接时,一旦关闭连接作为stdin
给出EOF
(其/dev/null
将做直线距离)。
击也有其自身内置的TCP / UDP服务,但他们是一个时间编译选项,我没有击编译它们: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标志是连接超时
使用-n标志与IP地址,而不是主机名的工作。
示例:
# `nc -z -w 1 -G 1 google.com 80`
# `nc -z -w 1 -G 1 -n 123.234.1.18 80`
我稍有改变克里斯·赖斯的回答。不过在处理一个单一的企图超时,但也允许多次重试,直到你放弃。
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
不隶属于 StackOverflow