2014-09-30 73 views
0

我有一個腳本,生成一個用戶指定的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 =>:關閉},狀態=:正在接收 賽璐珞:: TaskFiber backtrace不可用。如果您需要回溯,請嘗試Celluloid.task_class = Celluloid::TaskThread

並且該腳本根本不做任何事情。其餘的時間(只有當我指定超過1000)我得到這個:http://pastebin.com/wTmtPmc8

所以,我的問題是這樣的。我如何避免競爭條件和僵局,同時仍然能夠達到我想要的特定腳本?

回答

2

自行啓動低級別線程會干擾賽璐珞的功能。相反,請創建一個Scan對象池,並一次性向它們提供IP。他們將排隊等候購買

class Scan 
    def popen 
    … 
    end 
end 

scanner_pool = Scan.pool(50) 
resulsts = @host_arr.map { |host| scanner_pool.scan(host) }