套接字.io只向房间A和房间B的用户广播



是否可以制作套接字?向同时在房间a和房间B但不只是在房间a或房间B的命名空间的所有用户广播?

如果没有,我自己怎么去实现呢?是否有一种方法可以检索给定房间中名称空间中的所有用户?

我正在使用套接字。IO 1.0在节点

编辑:如果没有本机方法,我将如何创建自己的语法,例如:socket.broadcast.in('room1').in('room2').emit(...) ?

您可以使用(ref)查看房间的所有用户如何更新房间中所有客户端的套接字对象?(socket . io))

var clients = io.sockets.adapter.room["Room Name"]

所以给定两个数组为你的2个房间的花名册,你可以计算交集使用类似这里的答案(参考:最简单的代码数组交集在javascript中)

最后,你可以在两个房间的用户列表和发出事件使用(ref:如何更新套接字对象在房间的所有客户端?(socket.io))

//this is the socket of each client in the room.
var clientSocket = io.sockets.connected[clientId];
//you can do whatever you need with this
clientSocket.emit('new event', "Updates");

另一种方法当然是设置隐藏的房间,在那里你维护所有房间的组合,并在幕后向这些房间添加用户,然后你就可以简单地发射到那些隐藏的房间。但它面临着一个指数增长的问题。

没有内置的方法可以做到这一点。首先让我们看看广播是如何工作的:

https://github.com/Automattic/socket.io/blob/master/lib/namespace.js 206年…221 - 224年…230年

this.adapter.broadcast(packet, {
    rooms: this.rooms,
    flags: this.flags
});

现在我们知道每次广播都会创建一堆临时对象,indexOf查找,参数切片…然后调用适配器的广播方法。让我们看一下那个:

111 - 151年https://github.com/Automattic/socket.io-adapter/blob/master/index.js

现在我们正在创建更多的临时对象,并循环遍历房间中的所有客户端,如果没有选择房间,则循环遍历所有客户端。循环发生在encode回调中。该方法可以在这里找到:

https://github.com/socketio/socket.io-parser/blob/master/index.js

但是,如果我们不通过broadcast发送数据包,而是在遍历房间并找到同时存在于房间A和房间B中的客户端后分别向每个客户端发送数据包,该怎么办?

socket.emit在这里定义:https://github.com/Automattic/socket.io/blob/master/lib/socket.js

这就引出了client.jspacket方法:https://github.com/Automattic/socket.io/blob/master/lib/client.js

每个直接发出的数据包将被单独编码,这同样是昂贵的。因为我们向所有用户发送了完全相同的数据包。

回答你的问题

更改套接字。IO适配器类并修改广播方法,向原型添加自己的方法或通过继承适配器类滚动自己的适配器)。(var io = require('socket.io')(server, { adapter: yourCustomAdapter });)

或者覆盖socket.jsjoinleave方法。考虑到这些方法不经常被调用,并且您没有编辑多个文件的麻烦,这是相当方便的。

Socket.prototype.join = (function() {
    // the original join method
    var oldJoin = Socket.prototype.join;
    return function(room, fn) {
        // join the room as usual
        oldJoin.call(this, room, fn);
        // if we join A and are alreadymember of B, we can join C
        if(room === "A" && ~this.rooms.indexOf("B")) {
            this.join("C");
        } else if(room === "B" && ~this.rooms.indexOf("A")) {
             this.join("C");
        }  
    };
})();
Socket.prototype.leave = (function() {
    // the original leave method
    var oldLeave = Socket.prototype.leave;
    return function(room, fn) {
        // leave the room as usual
        oldLeave.call(this, room, fn);
        if(room === "A" || room === "B") {
             this.leave("C");
        }  
    };
})();

如果要广播到AB中的所有用户,则广播到C。这只是一个示例代码,您可以通过不硬编码房间名称,而是使用数组或对象来循环可能的房间组合来进一步改进这一点。

作为自定义适配器使socket.broadcast.in("A").in("B").emit()工作:

var Adapter = require('socket.io-adapter');
module.exports = CustomAdapter;
function CustomAdapter(nsp) {
  Adapter.call(this, nsp);
};
CustomAdapter.prototype = Object.create(Adapter.prototype);
CustomAdapter.prototype.constructor = CustomAdapter;
CustomAdapter.prototype.broadcast = function(packet, opts){
  var rooms = opts.rooms || [];
  var except = opts.except || [];
  var flags = opts.flags || {};
  var packetOpts = {
    preEncoded: true,
    volatile: flags.volatile,
    compress: flags.compress
  };
  var ids = {};
  var self = this;
  var socket;
  packet.nsp = this.nsp.name;
  this.encoder.encode(packet, function(encodedPackets) {
    if (rooms.length) {
      for (var i = 0; i < rooms.length; i++) {
        var room = self.rooms[rooms[i]];
        if (!room) continue;
        for (var id in room) {
          if (room.hasOwnProperty(id)) {
            if (~except.indexOf(id)) continue;
            socket = self.nsp.connected[id];
            if (socket) {
              ids[id] = ids[id] || 0;
              if(++ids[id] === rooms.length){
                socket.packet(encodedPackets, packetOpts);
              }
            }
          }
        }
      }
    } else {
      for (var id in self.sids) {
        if (self.sids.hasOwnProperty(id)) {
          if (~except.indexOf(id)) continue;
          socket = self.nsp.connected[id];
          if (socket) socket.packet(encodedPackets, packetOpts);
        }
      }
    }
  });
};

在你的app文件中:

var io = require('socket.io')(server, {
  adapter: require('./CustomAdapter')
});
io.sockets.adapter.room["Room A"].forEach(function(user_a){
  io.sockets.adapter.room["Room B"].forEach(function(user_b){
    if(user_a.id == user_b.id){
      user_a.emit('your event', { your: 'data' });
    }
  });
});

最新更新