2009-02-05 25 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`