簡體   English   中英

Ruby - 查看端口是否打開

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

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM