【问题标题】:Socket.IO Emit is emitting to all clientsSocket.IO Emit 正在向所有客户端发送
【发布时间】:2017-06-20 01:23:33
【问题描述】:

所以我正在用 NodeJS 编写一个应用程序,作为我的问题的前言,请了解我的设置当前是如何工作的:

我有客户端通过 Socket.io 连接到“服务器 X”,然后我的“服务器 X”通过 Socket.io 连接到“服务器 Y”,它们都通过 Socket.io 将数据发送回对方。

客户端 服务器 X 服务器 Y

客户端指的是用户及其浏览器,然后我的服务器 x 和服务器 y 上都运行了一个节点应用程序。

因此,在我的服务器 X 上的以下代码中,如果您查看第 4 行,它的工作原理与它应该完全一样。它只将消息发送给请求它的客户。

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

    // This works just fine.
    socket.emit('return_login', 'Test Message');

    socket.on('login', function(data){
        // This line correctly sends the data to Server Y
        server_y.emit('login', data);
    });

    server_y.on('return_login', function(data){
        // This emits to all connected clients???
        socket.emit('return_login', data);
    });

});

现在我的问题是当“服务器 Y”向服务器 x 发出 return_login 时,我希望服务器 x 获取服务器 y 发出的值并将其发送回原始客户端或 Web 浏览器.但由于某种原因,该行会发送到所有连接的客户端。

我有一台笔记本电脑,这台电脑和我的手机都在测试这个,每次发射都会发送给每个人。

如果有人可以帮我解决这个问题,我将不胜感激。如果我需要发布更多代码,请告诉我。

【问题讨论】:

    标签: node.js sockets express callback socket.io


    【解决方案1】:

    我不确定您的代码。但我通常使用空间向用户和套接字的回调函数发出。这是我使用回调而不是 return_login 事件

    的解决方案

    io.on('connection', function(socket){
        socket.on('login', function(data, callback){
            
            // Using callback instead of return_login event
            server_y.emit('login', data, function(responseData){
              
              // put this socket to room as name = user_id
              socket.join(responseData.user_id);
              
              // return result by callback
              callback(responseData)
            });
        });
    
    });
    
    // emit to exactly user_id with return_login event if you want
    io.to(user_id).emit('return_login', {key: 'ok'})

    【讨论】:

    • 我尝试了类似的方法,但这并不是我想要的。我很感激愿意提供帮助:)
    【解决方案2】:

    它正在发送到所有客户端,因为您为return_login 消息的每个套接字安装了一个单独的侦听器。因此,当一个客户端登录并将return_login 消息发送回您的服务器时,您对于每个看到该消息并将其转发到该套接字的单个套接字都有一个单独的侦听器。这样,它就会被发送到每个连接的套接字。

    解决这个问题的一种方法是确保return_login 消息只发送到它所属的套接字。如果您可以发送带有该消息的 socket.id 并让该服务器回显该 id 作为响应的一部分,那么您可以在收到消息时检查以确保仅将其发送到它所属的套接字。

    这是纯基于消息的系统的问题之一。您正在尝试执行请求/响应,只有请求者才能看到响应,但 socket.io 不是请求/响应系统。响应会发送给该特定消息的所有侦听器,并且由于您为连接的每个套接字都有该消息的侦听器,因此每个套接字都会看到它,然后将其转发到它的客户端。

    因此,通过对其他服务器进行相应修改以回显id 值,您可以这样做:

    io.on('connection', function(socket){
    
        // This works just fine.
        socket.emit('return_login', 'Test Message');
    
        socket.on('login', function(data){
            // add our id so we can identify our response back
            data.id = socket.id;
            server_y.emit('login', data);
        });
    
        let fn = function(data) {
            // check to see if this message is destined for this socket
            if (data.id === socket.id) {
                // make data copy with id value removed so 
                //   we don't send that to the client
                let tempData = Object.assign({}, data);
                tempData.delete(id);
                socket.emit('return_login', tempData);
                // we're done with this listener so remove it
                server_y.removeListener('return_login', fn);
            }
        });
    
        server_y.on('return_login', fn);
    
    });
    

    在您收到 return_login 消息后,可能很想删除您的侦听器,但如果两个客户端碰巧同时都在登录过程中,那么这会导致竞争条件,因此两者都有同时监听,那么第一条消息将被两个监听器接收到。

    【讨论】:

    • 你解决了我的问题,但我仍然很困惑。为什么要从该 tempData 对象中删除套接字 ID?您在评论中说删除了 id 值的数据副本,因此我们不会将其发送给客户端,但是您不想知道它们是什么套接字 id 吗?另外,我删除了 server_y.removeListener('return_login', fn); 行,因为它正在生成,所以您只能尝试一次登录。
    • @flakeyjake - 客户端不需要知道服务器端连接的socket.id,所以我想我会删除它以保持与您之前发送给客户端的相同数据结构.我认为这里没有理由将其发送给客户。如果您想避免删除它,您可以允许将其发送给客户端 - 无害。我不知道您想多次登录。是的,要做到这一点,您要么在发送登录消息时建立一个新的侦听器,要么不删除它。
    • @flakeyjake - 由于您可能是新来的,如果我的回答为您找到了解决方案,那么您可以通过单击答案左侧的绿色复选标记向社区表明这一点.遵循正确的程序,这也将为您赢得一些声誉积分。
    • 这更有意义@jfriend00,非常感谢您的帮助!我现在将其标记为答案
    猜你喜欢
    • 2016-10-19
    • 2017-08-17
    • 2019-08-04
    • 1970-01-01
    • 1970-01-01
    • 2022-11-15
    • 1970-01-01
    • 2014-08-17
    • 2018-01-30
    相关资源
    最近更新 更多