0

ユーザーが指定した数の IP アドレスを生成し、あるポートでそれらすべてに接続しようとするスクリプトがあります。2000 台のホストを同期的にスキャンするには時間がかかる可能性があるため、このスクリプトでは Celluloid を使用して適度な速度を実現しています。ただし、スクリプトに 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=: finalizer, meta={:method_name=>: shutdown }, status=:Celluloid::TaskFiber のバックトレースを受信中です。Celluloid.task_class = Celluloid::TaskThreadここでバックトレースが必要な場合は試してください。

スクリプトは何もしません。残りの時間 (1000 以上を指定した場合のみ) は次のようになります: http://pastebin.com/wTmtPmc8

だから、私の質問はこれです。この特定のスクリプトで目的を達成しながら、競合状態やデッドロックを回避するにはどうすればよいですか?

4

1 に答える 1

2

自分で低レベルのスレッドを開始すると、Celluloid の機能が妨げられます。代わりに、スキャン オブジェクトのプールを作成し、一度に IP をフィードします。彼らは利用可能なものを待ち行列に入れます

class Scan
   def popen
     …
   end
end

scanner_pool = Scan.pool(50)
resulsts = @host_arr.map { |host| scanner_pool.scan(host) }
于 2014-10-07T14:39:33.763 に答える