套接字.如何删除onConnect上注册的猫鼬事件侦听器

Socket.io Leak - How do I remove this mongoose event listener that is registered onConnect?

本文关键字:注册 侦听器 事件 onConnect 何删除 删除 套接字      更新时间:2023-09-26

当用户通过socket.io连接时,我有以下订阅:

    socket.on('subscribe', function(room) {
    console.log('joining room', room.id);
    socket.join(room.id);
    socket.roomName = room.id;
    // Insert sockets below
    require('../api/item/item.socket').register(socket);
  });

"项目。"Socket"代码为数据库事件(保存、删除等)附加mongoose事件处理程序,并在事件发生时发出Socket消息。下面是代码:

var Item = require('./it');
exports.register = function(socket) {
  Item.schema.post('save', function (doc) {
    console.log("hit save message");
    onSave(socket, doc);
  });
  Item.schema.post('update', function (doc) {
    console.log("hit update message");
    onSave(socket, doc);
  });
  Item.schema.post('remove', function (doc) {
    onRemove(socket, doc);
  });
};
function onSave(socket, doc, cb) {
  socket.emit(doc._id + ':item:save', doc);
}
function onRemove(socket, doc, cb) {
  socket.emit(doc._id + ':item:remove', doc);
}

当客户端断开连接时,执行以下代码:

function onDisconnect(socket) {
  console.log('disconnected: ' + socket.roomName);
  socket.leave(socket.roomName);
  socket.removeAllListeners("subscribe");
}

我遇到的基本问题是,如果用户连接到get那个项目。套接字猫鼬处理程序发送关于模型更改的更新。当它们断开连接(重新加载页面,离开,回来,等等),即使处理程序永远不会消失。例如,我更改了"item",如果我重新加载页面10次,我将得到10个"点击保存"消息。

理想情况下,当客户端离开页面时,该猫鼬处理程序将被销毁,因此它不会试图向任何人发送消息。

编辑:我很清楚,这是一个事件处理程序泄漏。基本上我需要做一些事情来销毁disconnect的handler。我需要以某种方式创建一个对require('../api/item/item.socket').register(socket);的引用,然后断开连接,取消注册,但我不知道如何正确地使用猫鼬模型和我设置它的方式。

function onDisconnect(socket) {
      console.log('disconnected: ' + socket.roomName);
      socket.leave(socket.roomName);
      socket.removeAllListeners("subscribe"); 
      //destroy handler here
    }

一个可能的解决方案如下。您可以维护在"item.socket"中连接的套接字集合。"项。然后将导出函数,以便在此集合中添加和删除套接字。所以,你会"require" item。在您的代码中使用一次套接字,然后在建立连接时使用套接字调用其add方法。类似地,当它断开连接时,您可以使用套接字调用它的remove方法。项中的猫鼬事件处理程序。套接字应遍历套接字集合,并在适用时发出消息。如果您希望以加载多个实例的方式"要求"该模块,则不妨将套接字集合附加到全局命名空间。

谢谢你的见解,有时候你只是盯着一个问题太久,然后意识到答案是直截了当的。我基本上按照你说的做了,只注册了一次item.socket。然而,我们没有保留一个套接字列表,而是使用socket.io方式将消息发送到正确的套接字,代码如下:

'use strict';
var Item = require('./item.model');
var log4js = require('log4js');
var logger = log4js.getLogger();
exports.register = function(socketio) {
  Item.schema.post('save', function (doc) {
    logger.debug("hit save message " + doc._id);
    onSave(socketio, doc);
  });
  Item.schema.post('update', function (doc) {
    logger.debug("hit update message");
    onSave(socketio, doc);
  });
  Item.schema.post('remove', function (doc) {
    onRemove(socketio, doc);
  });
};
function onSave(socketio, doc, cb) {
  socketio.sockets.in(doc._id).emit(doc._id + ':item:save', doc);
}
function onRemove(socketio, doc, cb) {
  socketio.sockets.in(doc._id).emit(doc._id + ':item:remove', doc);
}

其中doc._id为客户端订阅时加入的房间。泄漏固定! !谢谢:-)