Ruby - 查看端口是否打开

Chr*_*nch 43 ruby bash port network-programming

我需要一个快速的方法来确定一个给定的端口是否用Ruby打开.我目前正在摆弄这个:

require 'socket'

def is_port_open?(ip, port)
  begin
    TCPSocket.new(ip, port)
  rescue Errno::ECONNREFUSED
    return false
  end
  return true
end
Run Code Online (Sandbox Code Playgroud)

如果端口是打开的,它的效果很好,但是它的缺点是它偶尔会坐下等待10-20秒然后最终超时,抛出ETIMEOUT异常(如果端口关闭).我的问题是:

可以将此代码修改为仅等待一秒钟(false如果我们当时没有得到任何回报,则返回)或者是否有更好的方法来检查给定端口上的给定端口是否打开?

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

joa*_*ast 51

像下面这样的东西可能会起作用:

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
Run Code Online (Sandbox Code Playgroud)

  • 这个答案有一个解决方案,也适用于Windows:http://stackoverflow.com/a/3473208/362951 (2认同)
  • 不应该交换真/假吗? (2认同)

hip*_*ker 28

更多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
Run Code Online (Sandbox Code Playgroud)


ako*_*nov 16

所有其他现有答案都是不可取的 使用Timeout劝阻.也许事情取决于ruby版本.至少自2.0以来,人们可以简单地使用:

Socket.tcp("www.ruby-lang.org", 10567, connect_timeout: 5) {}
Run Code Online (Sandbox Code Playgroud)

对于旧版的ruby,我能找到的最佳方法是使用非阻塞模式然后select.这里描述:

  • 完美地为我工作:`port_is_open = Socket.tcp(host,port,connect_timeout:5){true} rescue false`.从单行扩展到拯救所需的特定异常很容易. (3认同)

Tob*_*hen 13

我最近提出了这个解决方案,使用了unix lsof命令:

def port_open?(port)
  !system("lsof -i:#{port}", out: '/dev/null')
end
Run Code Online (Sandbox Code Playgroud)

  • 这对我来说非常好.我想引入一个为vagrant中的虚拟机分配端口的系统,并编写这个单行程序来检查我要分配的端口是否打开:`vms ['port'] + = 1而端口.包括?vms ['port']或system("lsof -i:#{vms ['port']}") (2认同)

por*_*ges 10

只是为了完整性,Bash会是这样的:

$ netcat $HOST $PORT -w 1 -q 0 </dev/null && do_something
Run Code Online (Sandbox Code Playgroud)

-w 1指定1秒的超时时间,并-q 0说,当连接时,只要关闭连接stdin给出EOF(这/dev/null将做直线距离).

Bash也有自己的内置TCP/UDP服务,但它们是编译时选项,我没有用它们编译的Bash:P

  • 为了将来的参考,我在我的系统上发现它是`nc`而不是`netcat` (2认同)