2017-06-20 100 views
0

所以我在写一个的NodeJS应用程序,并作序,我的问题,请理解我的设置目前是如何工作的:Socket.IO的Emit被发射到所有客户端

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

客户< --->服务器X < --->服务器Ÿ

客户端是指用户和他们的浏览器,然后我有我的服务器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”发出return_login到服务器X,我希望发生什么是服务器X采取通过服务器Ÿ发出的价值,只是其发回给原来的客户端,或网页浏览器。但出于某种原因,该线路发射给所有连接的客户端。

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

如果有人可以请帮助我,我将不胜感激。如果我需要发布更多的代码,请让我知道。

回答

0

因为你已经安装了一个单独的侦听器的每个插座用于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消息您会收到它,但是如果两个客户端同时登录并因此同时拥有监听器,则会导致竞争状况,然后第一条消息将被两个监听器接收。

+0

你解决了我的问题,但我仍然困惑。为什么要从该tempData对象中删除套接字ID?你说在评论中删除ID值的数据副本,所以我们不会发送到客户端,但你不想知道他们是什么套接字ID?另外,我删除了'server_y.removeListener('return_login',fn)''这一行,因为它使得它只能尝试一次登录。 – flakeyjake

+0

@flakeyjake - 客户端不需要知道服务器端连接的'socket.id',所以我想我会删除它以保持与之前发送给客户端的数据结构相同。我没有理由想把它发送给客户。如果您想避免将其移除,您可以允许将其发送给客户端 - 无损。我不知道你想要多次登录。是的,要做到这一点,您要么在发送登录信息时建立新的听众,要么不要删除它。 – jfriend00

+0

@flakeyjake - 由于您看起来可能是新手,如果我的答案为您提供了解决方案,那么您可以通过单击答案左侧的绿色复选标记来向社区表明这一点。这也将为您遵循正确的程序赢得一些声望点。 – jfriend00

0

我不确定你的代码。但我通常使用空间来发送给用户和socket的回调函数。这是使用回调,而不是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'})

+0

我尝试了类似的东西,但它不完全是我在找的东西。我很欣赏愿意帮助,虽然:) – flakeyjake