无法发送给特定客户端:Socket IO会将其发送给每个客户端吗?

3

是的,我已经阅读了文档,文档写得非常好:Socket IO Cheatsheet

问题在于:当我的 Express 应用程序的会话被销毁时,我想通知用户进行注销。现在正在发生以下情况:当我从会话中注销时,所有其他客户端(包括那些尚未登录或根本没有登录的客户端)都会收到一条消息,说他们已经注销。是的,我的 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,你能给我举个详细的例子吗? - Aekansh Dixit
你正在编写服务器代码,好像一次只有一个用户在使用它。你不能将 current_socket 存储在全局可用的位置。因为不同的用户在服务器上执行不同的操作,这些操作会发生冲突。相反,你需要将用户状态存储在用户会话或直接存储在 cookie 中,然后当针对该特定用户的请求发生时,从该用户的会话或 cookie 中获取状态。 - jfriend00
2个回答

3

如果你想向特定用户发送emit消息,你需要为每个会话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 未定义。嗯。 - Aekansh Dixit

1

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

简单地说,我们使用用户ID(唯一)作为键来存储套接字对象(Map方式:key(userId)- value(socketObj))。

跟随兔子:

当用户登录时,客户端会向服务器端发出事件(login),该事件包括用户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中有任何异常吗? - Aekansh Dixit

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接