当您只需要将消息发送给一个客户端时,您肯定不希望将消息广播给所有客户端。您的方法 #1 就像在“上帝模式”下操作,可能只针对管理员。
我已经实现了与您的架构类似的架构。但是,我也使用 Redis 将我的客户端 ID(客户端名称)映射到套接字 ID,反之亦然。例如,您可以使用套接字 id 123 作为“omegalen”加入。然后由于某种原因断开连接,您会得到一个新的套接字 id:456。当我需要向“omegalen”发送消息时,我需要先在 Redis 中查找“omegalen”并获取您最近的套接字 id:456,因为 123 已经消失了,它将无法正常工作。这是一些示例代码,可以提供一个想法。请注意,我在密钥前面加上了命名空间,并且还为它们设置了过期时间(24 小时):
var client = redis.createClient(redisPort, redisHost);
function _updateSocketId(clientName, socketId) {
client.set("client/" + clientName, socketId);
client.set("socket/" + socketId, clientName);
client.expire("client/" + clientName, 1 * 24 * 60 * 60); //in seconds. 1 day
client.expire("socket/" + socketId, 1 * 24 * 60 * 60); //in seconds. 1 day
}
function _getSocketId(clientName, callback) {
//all clients are stored and prefixed with the namespace below
client.get("client/" + clientName, function(err, data) {
if(err) {
callback("Error retrieving key for " + clientName + "Error: " + err, null);
return;
}
var socketId = data;
logger.debug("Retrieved socket for client/" + clientName + ". Socket id: " + socketId);
callback(null, socketId);
});
}
function _findClientBySocket(socketId) {
var name = client.get("socket/" + socketId);
return name;
}
function _deleteSocketId(socketId, clientName) {
logger.debug("deleting socket: " + socketId + " - clientName: " + clientName);
client.del("socket/" + socketId);
client.del("client/" + clientName);
}
module.exports.getSocketId = _getSocketId;
然后,在设置我的 websocket 服务器时,我会监听事件并相应地更新客户端/套接字 id 映射:
socket.on("join", function (clientName, callback) {
//update Redis with new client id / socket id
redisUtil.updateSocketId(clientName, socket.client.id);
})
socket.on("rejoin", function (clientName) {
redisUtil.updateSocketId(clientName, socket.client.id);
})
socket.on("disconnect", function (clientName) {
redisUtil.deleteSocketId(socket.client.id, clientName);
})
上面的代码只是一个示例代码,可以让您了解一下,因为它还可以很容易地增强为每个客户端处理多个套接字(假设您打开了两个浏览器客户端)。你的架构图很好,它会工作,但你只需要向目标客户发送消息。
我不想跑题,但您也可以在 socket.io 中使用命名空间并向一组用户发出事件,例如,只向一种特殊类型的客户端发送事件:
var ssClients = io.of("/ssClients"); //socket.io namespace for the some ss clients
ssClients.on("connection", function (socket) {
..
这不是您的问题的一部分,但我认为如果您需要按命名空间广播/过滤消息,值得一提。
就 socket.io id 的唯一性而言,我从来没有遇到过这个问题。谷歌大规模地实施了类似的架构,他们没有遇到问题。您可以阅读它here。
我希望这会有所帮助;总体而言,您的架构非常好!