我需要一个快速的方法来确定一个给定的端口是否用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
如果我们当时没有得到任何回报,则返回)或者是否有更好的方法来检查给定端口上的给定端口是否打开?
编辑:只要它跨平台工作(例如,Mac OS X,*nix和Cygwin),调用bash代码也是可以接受的,尽管我更喜欢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
.这里描述:
https://spin.atomicobject.com/2013/09/30/socket-connection-timeout-ruby/
我最近提出了这个解决方案,使用了unix lsof
命令:
def port_open?(port) !system("lsof -i:#{port}", out: '/dev/null') end
只是为了完整性,Bash会是这样的:
$ netcat $HOST $PORT -w 1 -q 0
-w 1
指定1秒的超时时间,并-q 0
说,当连接时,只要关闭连接stdin
给出EOF
(这/dev/null
将做直线距离).Bash也有自己的内置TCP/UDP服务,但它们是编译时选项,我没有用它们编译的Bash:P
为了将来的参考,我在我的系统上发现它是`nc`而不是`netcat`