0

AWS Elasticache のクラスターと Redis を RedisStore バックエンドとして使用する nodejs/socket.io アプリケーションを作成しています。アプリは部屋の周りで重く動作します.Mobile Safari(iPad mini retina iOS7)だけが、サブスクライブしている部屋から退出するリクエストを送信した後、退出できない理由を理解するのに非常に苦労しています. クライアント側からの接続を閉じても、ソケットはサーバー上でハミングしたままになり、ルームへのサブスクリプションはそのまま残りますが、他のブラウザーは問題なく終了できます。

  1. NodeJS v0.10.25
  2. Socket.io v0.9.16
  3. Redis v2.8.6 (AWS エラスティックキャッシュ)
  4. Ubuntu 14.04 LTS (TCP モードのロードバランサーの背後にある EC2)

さて、私のコードでは、io.sockets.manager.roomClientsオブジェクトを使用して反復処理を行い、実際に使用されている部屋を確認しています。これはio.sockets.clients()、一定期間接続を開いたり閉じたりすると、レポートが完全に不正確なデータになるためです。

私のコードはここに置くには長すぎて、かなりプライベートですが、基本的に私が持っているものは次のとおりです。

サーバ:

if (cluster.isMaster) {

    function heartbeat(){
        // io.sockets.clients() doesn't splice dropped connections off the array
        // so we have to use io.sockets.manager.roomClients to see active rooms
        for( var i in io.sockets.manager.roomClients ) {
            console.log("Client:", i, io.sockets.manager.roomClients[i] );
        }
        setTimeout(heartbeat,5000);
    }

    heartbeat();

} else {

    io.sockets.on('connection', function (socket) {

        socket.on('subscribe', function (room) {
            console.log("Starting:",room);
            socket.join(room);
        });

        socket.on('unsubscribe', function (room) {
            console.log("Leaving:",room);
            socket.leave(room);
        });

        socket.on('disconnect', function () {
            console.log("Close Shop");
        });

    });
}

クライアント:

socket.emit('subscribe', 'some-room');

サーバーログ

Starting: some-room

そして、Client各タイムアウトティックでログを取得します:

Client: lhZsH1oL2vV7BML9QkSW { '': true, '/some-room': true }
Client: lhZsH1oL2vV7BML9QkSW { '': true, '/some-room': true }
Client: lhZsH1oL2vV7BML9QkSW { '': true, '/some-room': true }
Client: lhZsH1oL2vV7BML9QkSW { '': true, '/some-room': true }
Client: lhZsH1oL2vV7BML9QkSW { '': true, '/some-room': true }

さて、本題です。デスクトップ ブラウザの登録を解除または切断した場合:

socket.emit('unsubscribe', 'some-room');
Leaving: some-room

または

socket.disconnect();
Close Shop

目盛りは次のようになります。

Client: lhZsH1oL2vV7BML9QkSW { '': true }

私たちが知っているように、socket.io は接続のクリーンアップを苦手としていますが、少なくともルームのサブスクリプションはなくなっているためです。ただし、私のタブレットでは、購読を解除または切断した後、部屋の購読はio.sockets.manager.roomClientsオブジェクトに残ります。

Client: lhZsH1oL2vV7BML9QkSW { '': true, '/some-room': true }

私はソケットプログラミングにかなり慣れていないので、明らかな何かが欠けていると確信していますが、モバイル Websocket で同様の問題が発生した人はいますか?

4

1 に答える 1

0

そこで、独自の参照カウント方法を使用することで、socket.io を正確にする必要を回避できることを発見しました。既に Redis を使用して pubsub を介してソケットをサポートしているため、redis への別のクライアント接続を作成し、有効期限が切れたときに socket.id を setex します。ソケットがサブスクライブ解除または切断されると、socket.id に関連付けられた Redis のすべてのキーを削除します。このようにして、whos のインスタント スナップショットを取得し、何らかの理由で切断/サブスクライブ解除時にキーが削除されなかった場合、setex 呼び出しに設定した内容に基づいて有効期限が切れます。

私は自分の答えを正しいとマークするために、2日後に戻ってくることを忘れないようにします.

于 2014-05-19T07:06:59.280 に答える