【问题标题】:Can not send to specific client: Socket IO sends it to every client?无法发送到特定客户端:Socket IO 将其发送到每个客户端?
【发布时间】:2019-06-01 07:19:40
【问题描述】:

是的,我浏览了文档,写得很好: Socket IO Cheatsheet

问题出在:当 Express 应用程序的会话被销毁时,我想通知用户注销。现在正在发生这种情况:当我从会话中注销时,所有其他客户端(包括已登录或尚未登录的客户端)都会收到一条消息,说明他们已注销。是的,我的快速应用程序运行良好——他们没有被注销,但我相信 SOCKET IO 无论如何都会向他们发送消息。我运行了调试器,结果发现两个客户端也是可以区分的。

这是我的代码:

server.js:

var app = express();
var server = require('http').Server(app);
var io = require('socket.io')(server);
app.set('socketio', io);
io.on('connection', function (socket) {
  app.set('current_socket', socket);
  console.log('No of clients:', io.engine.clientsCount); 
});

userController.js:

exports.userLogout = function(req, res, next) {
    const sessionID = req.session.id;
    const io = req.app.get('socketio');
    const this_socket = req.app.get('current_socket');

    req.session.destroy(function (err){
        if(err) {
            console.error("userLogout failed with error:", err);
            return next(err);
        }
        else {
            console.log("this_socket:", this_socket);
            console.log("io:", io);
            this_socket.emit('userAction', { action: 'logout' });
            //other logic to remove old sessions from DB Session Store
            //and finally:
            res.status(200)
                .json({
                status: 'success',
                api_data: {'loggedIn':false},
                message: 'Logout successful.'
                });
        }
    }
}

我什至尝试过这个:

io.emit('userAction', { action: 'logout' });

但事实证明它仍然会发送给所有客户端。我很确定某处不匹配,只是不知道在哪里。

【问题讨论】:

  • @jfriend00 能给我一个详细的例子吗?
  • 您正在对您的服务器进行编码,就像一次只有一个用户在您的服务器上做事一样。您不能将current_socket 存储在全局可用的位置。由于不同的用户在你的服务器上做不同的事情,这些会发生冲突。相反,您需要将用户状态存储在用户会话中或直接存储在 cookie 中,然后当针对该特定用户的请求发生时,您会从该用户的会话或 cookie 中获取状态。

标签: javascript node.js express socket.io


【解决方案1】:

如果你想向特定用户发送发射,你需要为每个会话 ID 创建空间

io.on('connection', function (socket) {
  app.set('current_socket', socket);
  var sessionId = socker.request.session.id
  //join room
  socket.join(sessionId);
});

userController.js:

exports.userLogout = function(req, res, next) {
    const sessionID = req.session.id;
    const io = req.app.get('socketio');
    const this_socket = req.app.get('current_socket');

    req.session.destroy(function (err){
        if(err) {
            console.error("userLogout failed with error:", err);
            return next(err);
        }
        else {
            console.log("this_socket:", this_socket);
            console.log("io:", io);
            this_socket.sockets.in(sessionID).emit('userAction', { action: 'logout' });
            //other logic to remove old sessions from DB Session Store
            //and finally:
            res.status(200)
                .json({
                status: 'success',
                api_data: {'loggedIn':false},
                message: 'Logout successful.'
                });
        }
    }
}

【讨论】:

  • socket.request.session.id 未定义。嗯。
【解决方案2】:

您必须为每个用户定义唯一的套接字对象。我们有很多方法可以做到这一点。

简单来说,我们使用用户id(唯一)作为key来存储socket对象(映射方式:key(userId) - vaule(socketObj))。

跟随兔子:

当用户登录时,客户端向服务器端发出一个事件(登录),该事件包括用户ID。

客户端:

// login success
socket.emit('userLoggedIn', {userId: THE_USER_ID})

服务器端:

io.on('connection', function (socket) {
  // app.set('current_socket', socket);
  console.log('No of clients:', io.engine.clientsCount);
  socket.on('userLoggedIn', function(data) => {
    app.set(data.userId, socket); // save socket object
  })
});

userController.js:

exports.userLogout = function(req, res, next) {
    const sessionID = req.session.id;
    const userId = MAGIC_GET_USER_ID_FROM_SESSION_ID(sessionID) // who want to logout
    const io = req.app.get('socketio');
    const this_socket = req.app.get(userId); // get "user socket"

    req.session.destroy(function (err){
        if(err) {
            console.error("userLogout failed with error:", err);
            return next(err);
        }
        else {
            console.log("this_socket:", this_socket);
            console.log("io:", io);
            this_socket.emit('userAction', { action: 'logout' });
            //other logic to remove old sessions from DB Session Store
            //and finally:
            res.status(200)
                .json({
                status: 'success',
                api_data: {'loggedIn':false},
                message: 'Logout successful.'
                });
        }
    }
}

【讨论】:

  • 嘿!非常感谢你的建议。我确实意识到我的设置对流量不友好,因此我需要帮助使其对大量用户稳定。我是 Node 和 Socket 的新手。无论如何,我确实尝试实施您的解决方案,但不知何故“userLoggedIn”并没有被触发,尽管如此(这很奇怪),“userAction”被触发并且我在所有客户端上都收到一条注销消息。 pm2/node 中是否有任何问题?
猜你喜欢
  • 1970-01-01
  • 2015-07-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-24
  • 1970-01-01
  • 2015-11-21
  • 1970-01-01
相关资源
最近更新 更多