socket.io - 如何在命名空间上广播消息?

55

根据socket.io的示例:

要进行广播,只需将broadcast标志添加到emitsend方法调用中。广播意味着将消息发送给除了发起它的套接字以外的所有人。

var io = require('socket.io').listen(80);

io.sockets.on('connection', function (socket) {
  socket.broadcast.emit('user connected');
});

我尝试将此与新的socket.io命名空间功能结合起来,因此我得到了这个:

var chat = ioserver.of('/chat');

chat.on('connection', function (socket) {
      console.log('chat connection');   
      socket.on('message', function (msg) {
        console.log(msg);  
        chat.send(msg);
      });
  });

这个代码可以正常工作,所有人在聊天频道(而不是其他频道)都会接收到消息。但是发送者也会收到它。 所以我尝试了以下方法:

chat.on('connection', function (socket) {
      console.log('chat connection');   
      socket.on('message', function (msg) {
        console.log(msg);  
        chat.broadcast.send(msg);
      });
  });

然后我遇到了一个异常:'Cannot call method 'send' of undefined.' 那么,我认为广播是单个套接字的功能(尽管感觉有点奇怪——一个单独的套接字如何向所有其他套接字广播...)。 所以我尝试了:

chat.on('connection', function (socket) {
      console.log('chat connection');   
      socket.on('message', function (msg) {
        console.log(msg);  
        socket.broadcast.send(msg);
      });
  });

但现在情况变得更糟了 - 没有人收到消息,甚至发送者自己也没有收到。无论如何,这是我逻辑上所期望的 - 一个套接字无法通过它自身广播任何内容。这次没有异常,所以该套接字已定义广播。

如果我执行以下操作:

chat.on('connection', function (socket) {
      console.log('chat connection');   
      socket.on('message', function (msg) {
        console.log(msg);  
        socket.send(msg);
      });
  });

那么只有原始发送方接收到消息,这是相当合乎逻辑的——我使用了客户端相关套接字的“send”。

那么问题来了:如何正确使用广播功能?

也许socket.io的开发人员犯了一个错误,将广播功能添加到了错误的对象上(据我所知,它应该是命名空间的特性,但现在它仅针对套接字定义)?


你尝试过使用 chat.socket.broadcast 吗? - Raynos
@Raynos:谢谢你的想法,但是chat.socket.broadcast.send和chat.socket.broadcast仍然会抛出未定义异常。 - JustAMartin
4个回答

75

看起来我在开启悬赏后自己解决了这个问题。对此我表示抱歉。

无论如何,请看看下面的内容是否有帮助:

chat.on('connection', function (socket) {
  socket.on('message', function (msg) {
    socket.emit(msg); // Send message to sender
    socket.broadcast.emit(msg); // Send message to everyone BUT sender
  });
});

但是,如果不将消息重新发送给发送者,直接将其添加到聊天记录中,并可选择使用仅自我发出的方式确认已收到而无任何问题,您可以节省一些带宽并为用户创建更流畅的体验。


11
如果你使用 io.sockets.emit('signal', obj),会向所有人发送该信号。 - orloxx
这个例子应该在 Socket.IO 文档的顶部附近。大多数应用程序需要独立地回复每个连接,而不是无条件地广播给所有侦听器! - Cuadue
使用此代码,您可以将消息发送到名称空间中所有套接字,而不仅仅是特定房间的套接字。我说的对吗? - Dejan Bogatinovski
3
我不明白。在问题中,你说这段代码除了 socket.emit(msg); 以外,没有其他人收到信息。为什么加上 socket.emit(msg); 后,socket.broadcast.emit(msg); 突然会将信息发送给除发送者以外的所有人? - BlueRaja - Danny Pflughoeft

38

如果您在事件驱动的环境中工作,其中来自客户端的消息会触发对所有其他客户端的响应,则您的解决方案有效,但是如果您想要服务器向所有客户端发送消息,则无效。

您可以使用io.sockets.emit来实现此目的:

var io = require('socket.io').listen(80);
io.sockets.emit('message', { message: "Hello everyone!" });

然而,文档并没有明确说明如何针对特定的命名空间执行此操作。io.sockets只是io.of('')的一种快捷方式,因此通过调用io.of('/namespace').emit,您可以向命名空间中的所有人广播消息:

var io = require('socket.io').listen(80);
io.of('/admins').emit('message', { message: "Hello admins!" });

2
在我看来,这有点像混淆了套接字namespaceroom的术语。它们被分别处理。对于那些寻求将广播发送到特定房间(从服务器)的人,语法应为io.sockets.in('房间名').emit - Kirill Slatin
我不明白这个回答如何解决问题...问题是如何广播消息,你的回答将消息发送给每个人,这在 OP 的代码中已经起作用了。 - T J
仅供参考更新 - 在文档中没有提到服务器向所有客户端发出信号的特定方法。当你尝试使用< insert(io,namespace,socket) here>.emit时,你会发现它并不是容易理解的。他们的文档需要添加更多的示例,以便更好地理解。 - Nick Pineda
在这里救了我大忙!'sockets' vs io.of() - DanR

33
var customNS = ioserver.of('/chat'); 

customNS.on('connection', function (socket) {
   socket.on('message', function (msg) {

       // Send message to sender 
       socket.emit(msg);

       // Send message to everyone on customNS INCLUDING sender
       customNS.emit(msg);

       // Send message to everyone on customNS BUT sender
       socket.broadcast.emit(msg);

       // Send message to everyone on ROOM chanel of customNS INCLUDING sender
       customNS.in('ROOM').emit(msg); 

       // Send message to everyone on ROOM chanel of customNS BUT sender
       socket.broadcast.in('ROOM').emit(msg); 


   });
});

还可以查看这个答案:如何向除发送者之外的所有客户端发送响应(Socket.io)


将聊天更改为customNS。 - Marwen Trabelsi

14

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