【已解决】Nodejs中socket.io 如何保存所有人的连接?现在是第2个人连接上,第1个人就收不到socket消息

【已解决】Nodejs中socket.io 如何保存所有人的连接?现在是第2个人连接上,第1个人就收不到socket消息

更新了示例代码!

player = {};//注意:来自其他模块,并不是在本文件中定义的。用于保存所有用户的信息

io.sockets.on('connection', function (socket) {
	var currentUser = {//获取到的用户数据
		uid: 1000,
		socket: socket,
	};
	player[currentUser.uid] = currentUser;//保存用户连接

	currentUser.socket.on('login', function() {
	    currentUser.socket.emit('login_result', 'yes');
	});
	currentUser.socket.on('test', function() {
	    currentUser.socket.emit('test_result', 'something');
	});
});

在不使用session的情况下,可以用这种方式保存到所有用户的连接。

弊端嘛?人太多,player这个变量会很大很大。。

13 回复

【已解决】Node.js 中 socket.io 如何保存所有人的连接?现在是第2个人连接上,第1个人就收不到 socket 消息

问题描述

在使用 Node.js 和 socket.io 进行实时通信时,当第二个用户连接后,第一个用户就无法收到 socket 消息。我们需要找到一种方法来保存所有用户的连接,并确保每个用户都能接收到广播的消息。

解决方案

我们可以使用一个全局对象来存储所有用户的 socket 连接信息。这样,当有新的用户连接时,我们就可以将他们的 socket 对象添加到这个全局对象中,并且可以向所有用户发送消息。

以下是改进后的示例代码:

// 定义一个全局对象来保存所有用户的 socket 连接
const players = {};

io.sockets.on('connection', function (socket) {
    // 获取用户数据(这里只是一个示例,实际应用中应从其他地方获取)
    const currentUser = {
        uid: socket.id, // 使用 socket.id 作为唯一标识符
        socket: socket,
    };

    // 将当前用户添加到全局对象中
    players[currentUser.uid] = currentUser;

    // 监听登录事件
    socket.on('login', function () {
        socket.emit('login_result', 'yes');
    });

    // 监听测试事件
    socket.on('test', function () {
        socket.emit('test_result', 'something');
    });

    // 向所有用户广播消息
    socket.on('broadcast_message', function (message) {
        for (let user in players) {
            players[user].socket.emit('broadcast_message', message);
        }
    });
});

代码解释

  1. 全局对象 players:

    • 我们使用一个全局对象 players 来存储所有用户的 socket 连接信息。每个用户的 socket 都被存储在一个以 socket.id 为键的对象中。
  2. 监听连接事件:

    • 当一个新的 socket 连接建立时,我们将其添加到 players 对象中。
  3. 监听登录和测试事件:

    • 我们监听 logintest 事件,并向当前用户发送相应的响应。
  4. 广播消息:

    • 我们还监听了一个名为 broadcast_message 的事件,当接收到这个事件时,我们将消息广播给所有用户。

注意事项

  • 内存管理: 使用全局对象存储所有用户的 socket 连接可能会导致内存占用过高。建议定期清理不再活跃的用户连接,或者考虑使用其他更高效的数据结构或数据库来存储这些信息。

  • 安全性: 在实际应用中,应确保用户数据的安全性,避免潜在的安全风险。

通过上述改进,每个用户都可以正常接收消息,并且可以向所有用户广播消息。


看代码觉得没问题啊, socket 在函数闭包里边, 又没写成全局变量, 不会有覆盖呀

是必须用session么?我没有使用。

代码已更新

  • 应该是不会覆盖的啊
  • 当需要浏览器cookie来判断用户身份时,可用handshakeData得到sessionId,而且每个tab页面的socket是不一样的,所以即使userid唯一,也需要一个标识来指明到底消息来自于哪个tab,要发往哪个tab

请教哪里有handshakeData相关的代码示例?我在socket.io的github里都找到关于保持session相关的介绍。

io.configure(function() {
        io.set('transports', [ 'websocket', 'htmlfile', 'xhr-polling', 'jsonp-polling' ]);
        io.set('authorization', function(handshakeData, callback) {
            // 没有cookie则退出
            if (!handshakeData.headers.cookie) {
                return callback('no found cookie.', false);
            }

           var signedCookies = require('express/node_modules/cookie').parse(handshakeData.headers.cookie);
            handshakeData.cookies = require('express/node_modules/connect/lib/utils').parseSignedCookies(signedCookies, app.get('config')['session_secret']);

            // 根据sessionId找username
            sessionStore.get(handshakeData.cookies['sid'], function(err, session) {
                if (err || !session)
                    return callback('no found session.', false);
                handshakeData.session = session;
                if (handshakeData.session.user) {
                    return callback(null, true);
                }
                else {
                    return callback('no found session.user', false);
                }
            });
        });
    });

把player放到别的模块里面.然后提供add方法.这里调用的时候把socket传进去.socket就可以随时用了.

原来写过一个聊天室,我用的就是用数组保存登录进来的用户信息,之后再遍历数组发送消息出去,思路差不多是这样,好像socket.io有群发的API,很久木有关注这个了> <

又仔细看了一下.你的 uid 重复了.

那个UID只是伪代码,呵呵。谢谢。

这个你多实验一下就知道了

根据你提供的代码片段,你的目标是让每个客户端能够接收来自服务器的消息,并且新加入的用户也能够接收到其他用户的请求。问题在于,当前的实现方式使得每个用户只能接收到自己的消息。

为了解决这个问题,你需要维护一个全局的 sockets 对象,存储所有连接的 socket 实例。当新的消息到达时,你可以通过遍历这个对象来向所有的连接发送消息。

以下是一个修改后的示例代码:

let sockets = {}; // 用于保存所有用户的socket连接

io.sockets.on('connection', function(socket) {
    console.log("New user connected!");

    // 获取用户信息(此处简化处理)
    let currentUser = {
        uid: 1000, // 假设这是用户的唯一标识
        socket: socket,
    };

    // 将当前用户的socket添加到sockets对象中
    sockets[currentUser.uid] = socket;

    // 监听登录事件
    socket.on('login', function() {
        socket.emit('login_result', 'yes');
    });

    // 监听测试事件
    socket.on('test', function(data) {
        socket.emit('test_result', data);

        // 向所有用户广播消息
        for (let uid in sockets) {
            sockets[uid].emit('broadcast_test', data);
        }
    });
});

// 示例:向所有用户发送广播消息
function broadcastMessage(data) {
    for (let uid in sockets) {
        sockets[uid].emit('broadcast_message', data);
    }
}

在这个例子中,我们创建了一个 sockets 对象来存储所有连接的 socket。每当一个新的 socket 连接时,它会被添加到这个对象中。当接收到特定的事件(如 'test')时,不仅会向发起请求的用户发送响应,还会调用 broadcastMessage 函数,将消息广播给所有连接的用户。

这种方式可以确保所有用户都能接收到其他用户的请求,而不会因为新用户的连接导致旧用户的连接失效。不过需要注意的是,随着用户的增加,sockets 对象可能会变得非常大,因此需要考虑适当的清理机制或者使用数据库等更高级的方式来管理用户连接。

回到顶部
AI 助手
你好,我是IT营的 AI 助手
您可以尝试点击下方的快捷入口开启体验!