スレッドを使って同時にひたすらHTTPリクエストするスクリプト……のつもりだったが、うまく動かない。


require 'net/http'
Net::HTTP.version_1_2
 
host = 'XXX.XXX.XXX.XXX'
port = 'XXXX'
url_prefix = '/XXXX/XXXXXXX/'
pagesfile = 'pages.txt'
alltime = 180
 
pages = IO.readlines(pagesfile)
threads = []
 
begintime = Time.now
 
i = 0
while i < pages.size
  threads.push Thread.start {
    Net::HTTP.start(host, port) {|http|
      response = http.get(url_prefix + pages[i])
      #puts response.code
      #puts response.body
    }
  }
  i = i + 1
  sleep(alltime / pages.size)
end
 
threads.each { |t|
  t.join
}
 
endtime = Time.now
 
print "time = ", endtime - begintime, "\n"

Debian GNU/Linux 3.1 + ruby 1.8.2 での実行結果


$ ruby -v
ruby 1.8.2 (2005-01-10) [i386-linux]
$ ruby ./attack.rb
/usr/lib/ruby/1.8/net/http.rb:1556:in `read_status_line':
   wrong status line: "\211PNG" (Net::HTTPBadResponse)
    from ./attack.rb:31:in `join'
    from ./attack.rb:31
    from ./attack.rb:30:in `each'
    from ./attack.rb:30

CygwinCYGWIN_NT-5.0 1.5.10(0.116/4/2) + ruby 1.8.1 での実行結果


$ uname -a
CYGWIN_NT-5.0 1.5.10(0.116/4/2) i686 (一部略)
$ ruby ./attack.rb
/usr/lib/ruby/1.8/net/protocol.rb:83:
   [BUG] Segmentation fault
ruby 1.8.1 (2003-12-25) [i386-cygwin]
 
Aborted (core dumped)

Windows2000(SP4) + ruby 1.8.2 での実行結果


C:\>ruby -v
ruby 1.8.2 (2005-02-01) [i386-mswin32]
 
C:\>ruby attack.rb
C:/ruby/lib/ruby/1.8/net/http.rb:1556:in `read_status_line':
   wrong status line: "\211PNG" (Net::HTTPBadResponse)
    from attack.rb:31:in `join'
    from attack.rb:31
    from attack.rb:30:in `each'
    from attack.rb:30

コケる。スレッド数が2000件でも10件でもコケる。

アクセス先を画像PNGファイルではなくて、テキストHTMLに変更したら、


C:/ruby/lib/ruby/1.8/net/protocol.rb:197:in `sysread': 
   End of file reached (EOFError)
    from attack.rb:33:in `join'
    from attack.rb:33
    from attack.rb:32:in `each'
    from attack.rb:32

コケる。

例外を捕捉してみる。


i = 0
while i < pages.size
  threads.push Thread.start {
    Net::HTTP.start(host, port){|http|
      begin
        response = http.get(url_prefix + pages[i])
        #puts response.code
        #puts response.body
      rescue => e
        p e
      end
    }
  }
  i = i + 1
  sleep(alltime / pages.size)
end

#<Net::HTTPBadResponse: wrong status line: "\211PNG">

Net::HTTPBadResponse ねぇ……
Net::HTTPResponse のリファレンスを見ると、Net::HTTP#get はテキストページしか取得できないようにも見える。HTTPResponse のオブジェクトを取得するだけでも、ファイルをテキストとしてパースしちゃうのか?
でも、スレッドを使わない実装を別に作って実験したらうまくいった。
スレッドかなぁ……何が悪いのかわからんけど。

参考:

tags: zlashdot Ruby Ruby

Posted by NI-Lab. (@nilab)