我有一个脚本,它生成用户指定数量的 IP 地址并尝试在某个端口上全部连接到它们。我在这个脚本中使用赛璐珞以实现合理的速度,因为同步扫描 2000 台主机可能需要很长时间。但是,假设我告诉脚本扫描 2000 个随机主机。我发现它实际上只扫描了大约一半的数字。如果我告诉它扫描 3000,我会得到相同的基本结果。如果我做 1000 个或更少,它似乎工作得更好,但即使我只扫描 1000 个主机,它通常最终也只能以相对一致性完成大约 920 个。我意识到生成随机 IP 地址显然会失败,但我很难相信每次都有大约 70 个不正确生成的 IP 地址。所以这里是代码:
class Scan
include Celluloid
def initialize(arg1)
@arg1 = arg1
@host_arr = []
@timeout = 1
end
def popen(host)
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?
puts "#{host}:Firewalled"
end
begin
if sock.connect_nonblock(Socket.pack_sockaddr_in(22, addr[0][3]))
puts "#{host}:Connected"
end
rescue Errno::ECONNREFUSED
puts "#{host}:Refused"
rescue
false
end
end
sock
end
def asynchronous
s = 1
threads = []
while s <= @arg1.to_i do
@host_arr << Array.new(4){rand(254)}.join('.')
s += 1
end
@host_arr.each do |ip|
threads << Thread.new do
begin
popen(ip)
rescue
end
end
end
threads.each do |thread|
thread.join
end
end
end
scan = Scan.pool(size: 100, args: [ARGV[0]])
(0..20).to_a.map { scan.future.asynchronous }
大约一半的时间我得到这个:
D, [2014-09-30T17:06:12.810856 #30077] DEBUG -- : 终止 11 个演员... W, [2014-09-30T17:06:12.812151 #30077] WARN -- : 终止任务: type=:终结器,meta={:method_name=>: shutdown },status=:receiving Celluloid::TaskFiber 回溯不可用。
Celluloid.task_class = Celluloid::TaskThread
如果您需要回溯,请在此处尝试。
脚本什么也不做。其余时间(仅当我指定超过 1000 个时)我得到这个: http: //pastebin.com/wTmtPmc8
所以,我的问题是这个。如何避免竞争条件和死锁,同时仍然在这个特定脚本中实现我想要的?