我目前有一个用Ruby编写的脚本,它扫描一系列IP地址并尝试连接它们。目前它非常缓慢。扫描网络上的254台主机最多需要300秒,这显然不太实用。我试图做的是给脚本一些并发性,希望加快脚本速度。到目前为止,这就是我所拥有的:
require 'socket'
require 'celluloid'
$res_arr = []
class Ranger
include Celluloid
def initialize(host)
@host = host
@timeout = 1
end
def ip_range(host)
host =~ /(?:\d{1,3}\.){3}[xX*]{1,3}/
end
def ctrl(host)
begin
if ip_range(host)
strIP = host.gsub(/[xX*]/, '')
(1..254).each do |oct|
$res_arr << strIP+oct.to_s
end
else
puts "Invalid host!"
end
rescue
puts "onnection terminated."
end
end
def connect
addr = Socket.getaddrinfo(@host, nil)
sock = Socket.new(Socket.const_get(addr[0][0]), Socket::SOCK_STREAM, 0)
begin
sock.connect_nonblock(Socket.pack_sockaddr_in(22, addr[0][3]))
rescue Errno::EINPROGRESS
resp = IO.select(nil, [sock], nil, @timeout.to_i)
if resp.nil?
$res_arr << "#{@host} Firewalled!"
end
begin
if sock.connect_nonblock(Socket.pack_sockaddr_in(22, addr[0][3]))
$res_arr << "#{@host}Connected!"
end
rescue Errno::ECONNREFUSED
$res_arr << "#{@host} Refused!"
rescue
false
end
end
sock
end
def output(contents)
puts contents.value
end
end # Ranger
main = Ranger.new(ARGV[0])
main.ctrl(ARGV[0])
$res_arr.each do |ip|
scan = Ranger.new(ip)
scnftr = scan.future :connect
scan.output(scnftr)
end
该脚本可以工作,但它需要的时间与我之前的Celluloid一样长。我是否误解了赛璐珞的作用以及它应该做什么?
答案 0 :(得分:1)
你的问题是循环的每次迭代都会启动一个未来,然后立即等待它返回一个值。你想要的是开始所有期货,然后等待所有期货分两步完成:
futures = $res_arr.map do |ip|
scan = Ranger.new(ip)
scan.future :connect
end
# now that all futures are running, we can start
# waiting for the first one to finish
futures.each do |future|
puts future.value
end
这是赛璐珞来源的另一个例子:https://github.com/celluloid/celluloid/blob/master/examples/simple_pmap.rb