Socket.io断开相关闭包的事件和垃圾收集

Ale*_*lls 4 sockets closures websocket node.js socket.io

我有一个使用socket.io的基本实时服务器.我的问题涉及闭包和垃圾收集,以及我是否应该在关联数组中存储套接字连接,或者只是将它留给闭包来管理连接.

我遇到的一个问题是,如果套接字连接断开连接,如果在断开连接的套接字上调用emit,同一套接字连接是否会尝试发送消息?换句话说,当您在断开连接的套接字上调用socket.emit()时会发生什么?

这是一些代码,底部的问题:

 var socketio = require('socket.io);
 var io = socketio.listen(server);
 var EE = require('events').EventEmitter;
 var ee = new EE(); //this is actually initialized elsewhere but now you know what it is

 var connectedUsers = {}; //associative array to store socket connections by socket.id

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

           connectedUsers[socket.id] = socket;  //should I bother storing the socket connections in the associative array or just leave it to the closure to store them

            socket.on('disconnect', function () {
                connectedUsers[socket.id] = null; //should I bother removing
            });

            ee.on('update',function(data){

                socket.emit('update',JSON.stringify(data));

            });

            ee.on('insert',function(data){

                socket.emit('insert',JSON.stringify(data));

            });

            ee.on('delete',function(data){

                socket.emit('delete',JSON.stringify(data));

            });
        });
    }
Run Code Online (Sandbox Code Playgroud)

因此,我的主要问题是,用于闭包的内存量将随套接字连接的数量呈线性增长,并且永远不会停止或减少.socket.io断开事件是否通过垃圾回收释放内存?

似乎我需要重新组织上面的代码来完成两件事:

  1. 允许垃圾收集,以便服务器内存占用不会无限增长

  2. 避免为每个套接字连接发布所有数据,这就是它现在正在做的事情.

这准确吗?

Pet*_*ons 8

我遇到的一个问题是,如果套接字连接断开连接,如果在断开连接的套接字上调用emit,同一套接字连接是否会尝试发送消息?换句话说,当您在断开连接的套接字上调用socket.emit()时会发生什么?

否..emit()对断开连接的套接字的任何调用都将被忽略.这是相关的源代码片段.

connectedUsers[socket.id] = socket;
//should I bother storing the socket connections in the
// associative array or just leave it to the closure to store them
Run Code Online (Sandbox Code Playgroud)

你不应该存储它们.把它留在封闭处.然后不需要将它们设置为null.

因此,我的主要问题是,用于闭包的内存量将随套接字连接的数量呈线性增长,并且永远不会停止或减少.socket.io断开事件是否通过垃圾回收释放内存?

是的,当套接字断开连接时,将发布垃圾收集的东西.socket.io将从它的内部队列中删除它们,没有任何东西可以引用它们,它们将有资格进行垃圾回收.但是,上面的代码与发送事件的方式不一致.请参阅下文了解详情.

ee.on('update',function(data){
   socket.emit('update',JSON.stringify(data));
});
Run Code Online (Sandbox Code Playgroud)

不要这样做这种模式.问题是你从来没有removeListener在每个'update'事件上调用这样的事件,你将为进程启动后连接的每个套接字执行这些回调之一,即使是断开连接的套接字.那是你的泄密.相反,对于这种模式,只需在闭包之外设置一次并且只设置一次:

ee.on('update', function (data) {
  io.sockets.emit('update', data);
});
Run Code Online (Sandbox Code Playgroud)

(除此之外:JSON.stringify几乎肯定是不必要的.只有你真的知道你必须把它作为一个字符串放在另一边.只是发射一个对象可能是正确的事情)

现在,对于需要发送到特定套接字而不是所有连接套接字的情况,您应该使用命名函数,以便您可以将每个ee.on与相应的对配对,ee.removeListener以正确防止幻像侦听器.

io.on('connection', function(socket) {
  // every socket gets a closure
  // and a distinct onUpdate function object
  function onUpdate(data) {
    socket.emit('update', data);
  }
  ee.on('update', onUpdate);

  socket.on('disconnect', function() {
    // removes the handler for this specific socket,
    // leaving the others intact
    ee.removeListener('update', onUpdate);
  });
});
Run Code Online (Sandbox Code Playgroud)