大津です。

これは http.Agent に関する非常に良い課題だと思います。

# 本当は XXXX の YYYY を見てくださいと言いたいところなんですけど、それは
今後の楽しみにしていただけるとありがたいです。

> nodeに興味が出て、勉強のprogramを書いてるところです。
> javascript自体、ecma 
> scriptの仕様書を見ながら書いているレベルなので、node自体の使い方の質問では無く、javascriptの質問になっているかもしれませんが、その際は指摘していただければと思います。

いえJSの問題ではなく Node.js 固有の原因によるものですので安心してください。

> 書いているのは、httpへの負荷をかけるツールです。
> 書いたcodeを質問用に簡略化したのが、
(中略)
> のようなwarningが出ます。

まず Node.js のHTTPクライアントの動作について少し解説が必要かなと思います。

Node では、通常 http.request() で生成したリクエストオブジェクト(req)が
HTTPサーバに接続する際、リクエストオブジェクトが直接 HTTPサーバにソケッ
ト接続するのではなく、http.Agent が替りにソケット接続を行い、ソケットと
リクエストを結びつける管理する役割を担います。

ソケットの最大同時接続数は http.Agent.maxSockets の値が上限で、それを超
えるとリクエストは queue に溜まります。
Agent は接続したソケットをHTTPリクエストに割り当て、HTTPリクエストが終了
すると Agent は既存のソケットを使いまわして他のリクエストに再度割り当て
ます。(HTTP keep-alive が有効になっていることが前提です。)

リクエストの際、特に Agent の指定をしなればデフォルトで globalAgent が利
用され、最大同時接続数は5つに制限されています。(管理単位は
host+port+sourceIP)

上記の知識を前提として以下に回答を書いてみます。

> 疑問なのが
> 1.
> 51行目で、走ると思われる並列数分setMaxListeners()しているのに、それ以上のlistenerを追加しようとしているのはなぜ?

'socket' イベントで渡される socket オブジェクトはデフォルト(globalAgent
利用時)では5つです。毎回 golbalAgent がリクエストに socket を割り当てる
度にその5つに対してリスナ追加をするので setMaxListners() 値を超えてし
まっています。

> 2.
> そもそも、http接続毎に生成されるhttp.ClientRequest用のsocketのconnect 
> eventを、once()でつかまえようとしているのに、複数回のlistener登録が行なわれるのはなぜ?
> 

globalAgent 利用時 socket は 'connect' イベントは最初に接続した5回分しか
emit しません。(途中で接続が他の理由で切れない前提ですけど)
なのでいくら once でリスナ登録しても emit されないのでリスナは次々登録さ
れる状況になります。

> 3.
> 結局どう書くのがnode流なの?

うーん、いろいろやり方があります。100個ぐらいなら一気に http.request()
してやればメモリは多少使いますが、 Agent が勝手に接続をしてくれるでしょう。

スケールするよう最大接続数を parallel のカスタムエージェントを作って、レ
スポンス終了毎に順次リクエスト追加するやり方場合を下記 gist に置きました。

https://gist.github.com/2781370

コメントとか書いていませんが、今後の参考にしていただけたらと思います。
(gjslint ベースに書式は変えてます。)

メールによる返信