2009-02-05 77 views
38

我需要一个快速的方法来确定给定的端口是否用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)还是有更好的方法来检查给定端口是否在给定主机上打开?

编辑:尽管我更喜欢Ruby代码,但只要它可以跨平台工作(例如,Mac OS X,* nix和Cygwin),调用bash代码也是可以接受的。

回答

43

类似以下可能的工作:

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 
+0

就像一个魅力!谢谢! – 2009-02-05 20:36:47

+0

我遇到了阻塞问题(我认为)。基本上超时不会超时。不知道为什么,但netcat解决方案在其位置上运行良好。 – 2011-10-27 16:26:52

+2

此答案有一个也适用于Windows的解决方案:http://stackoverflow.com/a/3473208/362951 – mit 2012-07-08 20:22:25

10

只是为了保持完整性,猛砸会是这样的:

$ netcat $HOST $PORT -w 1 -q 0 </dev/null && do_something 

-w 1指定1秒的超时和-q 0说,当连接时,尽快关闭连接stdin给出EOF(其中/dev/null将立即执行)。

击也有其自身内置的TCP/UDP服务,但他们是一个时间编译选项,我没有击与他们编译:P

26

更多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 
1

我对Chris Rice的回答略有差异。仍然处理一次尝试超时,但也允许多次重试,直到你放弃。

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 
9

最近,我想出了这个解决方案,使得UNIX lsof命令的使用:

def port_open?(port) 
    !system("lsof -i:#{port}", out: '/dev/null') 
end 
2

所有* 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`