[英]Ruby - See if a port is open
I need a quick way to find out if a given port is open with Ruby.我需要一种快速的方法来确定给定的端口是否已使用 Ruby 打开。 I currently am fiddling around with this:
我目前正在摆弄这个:
require 'socket'
def is_port_open?(ip, port)
begin
TCPSocket.new(ip, port)
rescue Errno::ECONNREFUSED
return false
end
return true
end
It works great if the port is open, but the downside of this is that occasionally it will just sit and wait for 10-20 seconds and then eventually time out, throwing a ETIMEOUT
exception (if the port is closed).如果端口打开,它工作得很好,但它的缺点是偶尔它会坐下来等待 10-20 秒,然后最终超时,抛出
ETIMEOUT
异常(如果端口关闭)。 My question is thus:我的问题是:
Can this code be amended to only wait for a second (and return false
if we get nothing back by then) or is there a better way to check if a given port is open on a given host?是否可以将此代码修改为仅等待一秒钟(如果到那时我们一无所获,则返回
false
),或者是否有更好的方法来检查给定主机上的给定端口是否打开?
Edit: Calling bash code is acceptable also as long as it works cross-platform (eg, Mac OS X, *nix, and Cygwin), although I do prefer Ruby code.编辑:调用 bash 代码也是可以接受的,只要它跨平台工作(例如,Mac OS X、*nix 和 Cygwin),尽管我更喜欢 Ruby 代码。
Something like the following might work:像下面这样的东西可能会起作用:
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
More Ruby idiomatic syntax:更多 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
All other existing answer are undesirable.所有其他现有答案都是不可取的。 Using
Timeout
is discouraged . 不鼓励使用
Timeout
。 Perhaps things depend on ruby version.也许事情取决于 ruby 版本。 At least since 2.0 one can simply use:
至少从 2.0 开始可以简单地使用:
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
.对于较旧的 ruby,我能找到的最佳方法是使用非阻塞模式,然后
select
. Described here:这里描述:
I recently came up with this solution, making use of the unix lsof
command:我最近想出了这个解决方案,使用 unix
lsof
命令:
def port_open?(port)
!system("lsof -i:#{port}", out: '/dev/null')
end
Just for completeness, the Bash would be something like this:为了完整起见,Bash 将是这样的:
$ netcat $HOST $PORT -w 1 -q 0 </dev/null && do_something
-w 1
specifies a timeout of 1 second, and -q 0
says that, when connected, close the connection as soon as stdin
gives EOF
(which /dev/null
will do straight away). -w 1
指定 1 秒的超时, -q 0
表示,连接后,只要stdin
给出EOF
就关闭连接( /dev/null
将立即执行)。
Bash also has its own built-in TCP/UDP services, but they are a compile-time option and I don't have a Bash compiled with them :P Bash 也有自己的内置 TCP/UDP 服务,但它们是一个编译时选项,我没有用它们编译 Bash :P
My slight variation to Chris Rice's answer.我对克里斯赖斯的回答略有不同。 Still handles timing out on a single attempt but also allows multiple retries until you give up.
仍然处理一次尝试超时,但也允许多次重试,直到您放弃。
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
All *nix platforms:所有 *nix 平台:
try nc / netcat command as follow.尝试 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
The -z flag can be used to tell nc to report open ports, rather than initiate a connection. -z 标志可用于告诉 nc 报告打开的端口,而不是启动连接。
The -w flag means Timeout for connects and final net reads -w 标志表示连接和最终网络读取超时
The -G flag is connection timeout in seconds -G 标志是以秒为单位的连接超时
Use -n flag to work with IP address rather than hostname.使用 -n 标志来处理 IP 地址而不是主机名。
Examples:例子:
# `nc -z -w 1 -G 1 google.com 80`
# `nc -z -w 1 -G 1 -n 123.234.1.18 80`
My solution is derived from the posted solutions.我的解决方案来自已发布的解决方案。
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.