NodeJS + Cluster + Socket.io + Redis - 断开连接后iOS不会离开房间

时间:2014-05-18 22:46:02

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

我正在编写一个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(TCP模式下负载均衡器后面的EC2)
  5. 现在,在我的代码中,我一直在使用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 }
    

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

1 个答案:

答案 0 :(得分:0)

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

我会记得两天后回来将我自己的答案标记为正确。