【问题标题】:NodeJS + Cluster + Socket.io + Redis - iOS not leaving rooms after disconnectNodeJS + Cluster + Socket.io + Redis - iOS 在断开连接后不离开房间
【发布时间】:2014-05-18 22:46:02
【问题描述】:

我正在编写一个 nodejs/socket.io 应用程序,它使用 AWS Elasticache 中的集群和 Redis 作为 RedisStore 后端。该应用程序在房间周围大量工作,我很难理解为什么只有 Mobile Safari(iPad mini Retina iOS7)在发出请求后不能离开它订阅的房间。即使从客户端关闭连接也会使套接字在服务器上嗡嗡作响,并且对房间的订阅完好无损,但其他浏览器可以毫无问题地退出。

  1. NodeJS v0.10.25
  2. Socket.io v0.9.16
  3. Redis v2.8.6 (AWS Elasticache)
  4. Ubuntu 14.04 LTS(EC2 在 TCP 模式下的负载均衡器后面)

现在,在我的代码中,我一直在使用 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 }

我在套接字编程方面相当新,所以我确定我遗漏了一些明显的东西,但是有没有人在移动 websockets 方面遇到过类似的问题?

【问题讨论】:

  • 我偶尔也会遇到这种情况。通常套接字最终会断开连接,但那是在几分钟后.. 希望你能找到答案!
  • @lawm,谢谢!是的,果然,在让它静置几分钟后,客户端队列被清除了。我可能最终只是暂时放手,但如果这项服务变得很大,我想找到一种方法来强制删除东西以释放内存。我会发布任何更新

标签: node.js socket.io mobile-safari node-redis amazon-elasticache


【解决方案1】:

所以我发现通过使用我自己的引用计数方法,我可以绕过需要 socket.io 来准确。由于我已经在使用 Redis 通过 pubsub 支持我的套接字,所以我只需创建另一个到 redis 的客户端连接,并在过期时设置 socket.id。当我的套接字取消订阅或断开连接时,我删除了 Redis 中与 socket.id 关联的所有键。这样,我就有了 whos on 的即时快照,如果由于某种原因密钥在断开/取消订阅时没有被删除,它将根据我为 setex 调用设置的内容过期。

我会尽量记住在两天后回来将我自己的答案标记为正确。

【讨论】:

  • 我知道这是旧的但有机会分享您的代码吗?
猜你喜欢
  • 1970-01-01
  • 2012-11-09
  • 2017-03-21
  • 1970-01-01
  • 2014-09-28
  • 1970-01-01
  • 1970-01-01
  • 2017-01-05
  • 1970-01-01
相关资源
最近更新 更多