本多@hakobera です。

以前に xhr-polling で動かした記憶があったのでおかしいなと思い、
調べてみたら、これ、socket.io-client のバグですね。

2つのバグが混ざっています。(2つ目は仕様かもしれませんが)

1つ目は node 上での XHR の check メソッド内のバグ。

具体的には、v0.9.3 で以下のコミットが入ったためです。

https://github.com/LearnBoost/socket.io-client/commit/b8c3f799363075d6ea9c2065cac59a58d660d7e4

0.9.10 だと少し変数名が変わっていますが、以下の行です。

https://github.com/LearnBoost/socket.io-client/blob/master/lib/transports/xhr.js#L193

node 環境だと global.location が undefined であるために例外が発生し、
XHR.check() が常に false を返すため、Socket の生成に失敗し、コネクションが張れない(socket.js
の225行目で connect_failed イベントが発生する)ので、最終的に timeout してしまうのです。

https://github.com/LearnBoost/socket.io-client/blob/master/lib/socket.js#L225

これに関しては既に pull-request も上がっていますね。全然取り込まれないですけど。

https://github.com/LearnBoost/socket.io-client/pull/420

なので、現時点での対応策としては、

1. 負荷テスト側では socket.io-client の 0.9.2 を使う
2. socket.io-client を fork して修正したものを使う(修正方法は上記 pull request を参照)
3. socket.io-client が修正されるのを待つ

のいずれかになると思います。

2つ目のバグ(仕様?)は、
io.connect の option で transports を1つしか指定しなくても、
io.transports の設定が混ざりこんでしまうという問題です。

transport 固定しているのに以下の動きがおかしいなと思ったのです。

> xhr-polling指定   -->  指定なし              (websocketに切り替わって動作)

でも、実際にやってみたら、確かに websocket に切り替わるので、調べてみると、
Socket.transports のデフォルト値に io.transports が指定されており、
これが [ 'xhr-polling', 'websocket' ] という値であるためでした。

https://github.com/LearnBoost/socket.io-client/blob/master/lib/socket.js#L23-42

指定された option.transports も merge しているのですが、
io.util.merge の実装で配列の merge は要素の追加なので、websocket という値が残ってしまい、server 側が
websocket 優先の設定になっていると、そちらで繋がってしまう、という状況でした。

これも socket.js の実装が以下のようになっていれば良いと思うんですが

this.options = {
...
 , transports: options.transports ? [] : io.transports
...
}

なっていないので、以下のように io.connect() を呼び出す直前で、
io.transports を書き換えることで一応回避できます。

var io = require('socket.io-client');

io.transports = ['xhr-polling'];
var socket_xhr = io.connect(uri, {
  'try multiple transports': false,
  'force new connection': true
});

io.transports = ['websocket'];
var socket_ws = io.connect(uri, {
  'try multiple transports': false,
  'force new connection': true
});

もしくは server 側の transports の優先順位を xhr-polling -> websocket の順番にするかですね。

2012年8月28日 2:14 atsuya <[email protected]>:
> こんにちは、高木です。
>
> "force new connection"オプションは指定されましたか?
>
> - 高木
>
>
> 2012/8/27 uchida75cm <[email protected]>:
>> @hakoberaさん
>> やりたい負荷テストは、おしえて頂いた方法で実現できそうです!
>> ありがとうございます。
>>
>> socket.io-clients側のtransportのoptionを指定してみたのですが、
>> うまくxhr-pollingで接続できず、タイムアウトになってしまう状況です。
>>
>> 環境は下記のような環境です。
>> OS: CentOS release 5.7 (Final)
>> Node: v0.6.19
>> Socket.IO: v0.9.10
>> Socket.IO-Client: v0.9.10
>>
>> いくつか試したパターンは下記のような結果でした。
>> client                  -->   server
>> 指定なし            -->  指定なし              (websocketで問題なく動作)
>> 指定なし            -->   xhr-polling指定    (タイムアウト)
>> xhr-polling指定   -->  指定なし              (websocketに切り替わって動作)
>> xhr-polling指定   -->  xhr-polling指定     (タイムアウト)
>>
>> ※ 動作したと判断している場合は、「任意に指定しているイベントのやりとりができた」
>>  という状態です。
>> ※ タイムアウトになる場合も、server側のログでは、authorizationを通り、
>>  socket.idが発行されているようでした。
>>
>> nodeやmoduleのバージョンでうまく動いていないかもしれないので、
>> バージョンなどを変えてもう少し触ってみます。ソースなども少し追ってみます。
>>
>> 何か進展があればまたこちらに書きたいと思います。
>> また相談させて頂くかもしれませんが、よろしくお願いします。
>>
>>
>>
>>
>>
>>
>>
>> 2012年8月27日月曜日 16時48分03秒 UTC+9 hakobera:
>>>
>>> 本多@hakobera です。
>>>
>>> 複数の transport が混在した環境をテストしたいというのであれば、
>>> transport 層を固定したクライアントを option 指定で別々に作れば良いのではないでしょうか。
>>>
>>> var uri = 'http://domain.com';
>>>
>>> // for WebSocket
>>> var socket_ws =  io.connect(uri, {
>>>   transports: [ 'websocket' ],
>>>   'force new connection': true
>>> });
>>>
>>> // for XHR-Polling
>>> var socket_xhr =  io.connect(uri, {
>>>   transports: [ 'xhr-polling' ],
>>>   'force new connection': true
>>> });
>>>
>>> 各オプションの詳細は以下を参照してください。
>>> https://github.com/LearnBoost/socket.io-client#options
>>>
>>> force new connection はマニュアルに書いてないですが、
>>> これ書かないと、同じURLの場合にコネクションが使いまわされてしまい、
>>> 何個ソケット作っても実質1クライアントで負荷テストになりまし、
>>> 2つめ以降の options の設定が効きません。
>>>
>>>
>>> https://github.com/LearnBoost/socket.io-client/blob/master/lib/io.js#L192-200
>>>
>>> 2012年8月27日 16:21 uchida75cm <[email protected]>:
>>> > こんにちは、uchida75cmといいます。
>>> >
>>> > Socket.IOサーバを使ったサービスの負荷テストをしたいと考えています。
>>> > transportsがwebsocketだけの場合には、socket.io-clientsなどで、
>>> > 複数接続を行い、検証することができるかと思うのですが。
>>> >
>>> > IEなど、xhr-pollingを利用するブラウザが混ざってくるような場合の環境を
>>> > シミュレーションして、負荷テストする方法はないでしょうか。
>>> >
>>> > 何か良い方法があればご教授いただけると幸いです。
>>> > よろしくお願いします。
>>> >
>>> > --
>>> >
>>> >
>>> >
>>
>> --
>>
>>
>>
>
> --
>
>
>

-- 



メールによる返信