是否可以制作套接字?向同时在房间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.js
的packet
方法:https://github.com/Automattic/socket.io/blob/master/lib/client.js
每个直接发出的数据包将被单独编码,这同样是昂贵的。因为我们向所有用户发送了完全相同的数据包。
回答你的问题
更改套接字。IO适配器类并修改广播方法,向原型添加自己的方法或通过继承适配器类滚动自己的适配器)。(var io = require('socket.io')(server, { adapter: yourCustomAdapter });
)
或者覆盖socket.js
的join
和leave
方法。考虑到这些方法不经常被调用,并且您没有编辑多个文件的麻烦,这是相当方便的。
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");
}
};
})();
如果要广播到A
和B
中的所有用户,则广播到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' });
}
});
});