Redis Pub/Sub 聊天室

Posted

技术标签:

【中文标题】Redis Pub/Sub 聊天室【英文标题】:Redis Pub/Sub ChatRooms 【发布时间】:2016-01-18 08:19:26 【问题描述】:

我对 Redis Pub/sub 很陌生,所以请多多包涵。我正在尝试创建一个 IRC,用户可以在其中创建自己的聊天室,有点像 Gitter。以下是我到目前为止所做的事情。我通过用户名为用户订阅不同的频道只是为了测试。问题是当我发布到频道 x 时,被订阅频道 y 的客户仍然得到相同的结果消息.. 我正在使用 redis-cli 和 PUBLISH 命令发布。

function handleIO(socket)
    function disconnect()
        console.log("Client disconnected");
        socket.broadcast.emit("user d/c", socket.username+" has left!");
    

    socket.on("new user", function(username)
        socket.username = username;

        if(socket.username == "chat")
            redisClient.subscribe("chat");
        else
            redisClient.subscribe("other");
        

        socket.userColor = '#'+(Math.random()*0xFFFFFF<<0).toString(16);
        socket.emit("new_user", username);

        emitter.lrange("messages", 0, -1, function(err, messages)
            //reversing to be in correct order
            messages = messages.reverse();

            messages.forEach(function(message)
                message = JSON.parse(message);
                socket.emit("messages", message);
            );
        );

        socket.broadcast.emit("user connection", username+" has connected to the Haven!");
    );
    socket.on("disconnect", disconnect);

    socket.on("send", function(msg)
        var msg = JSON.stringify(  name: socket.username, messageText: msg, color: socket.userColor  );

        emitter.lpush("messages", msg, function(err, response)
            //keep newest 10 items
            emitter.ltrim("messages", 0, 9);
        );
        io.sockets.emit("receive", msg, socket.userColor);
    );
    redisClient.on("message", function (channel, message) 
        console.log(channel+":"+message);
        socket.emit("message", channel, message);
    );


【问题讨论】:

【参考方案1】:

对于迷路的流浪者......我所做的是在客户端上实现另一个事件,以基本上检查该客户端是否“有权”接收消息(即消息的频道是否属于客户端的子频道列表,如果这就说得通了)。

客户端

socket.on("message", function(channel, message)
     socket.emit("entitled", channel, message);
);

socket.on("entitled", function(reply, channel, message)
     if(reply == 1)
          $("#msgArea").append(message+"<br/>");
          $("#msgArea").prop( scrollTop: $("#msgArea").prop("scrollHeight") );    
     
);

服务器端

socket.on("entitled", function(channel, message)
    //check that user is subbed 
    emitter.sismember('channels:'+socket.username, channel, function(err, reply)
        if(err) throw err;
        socket.emit("entitled", reply, channel, message);
    );
);

我故意遗漏的是,我没有继续使用 socket.username,而是开始使用会话来保持持久性。我的建议是坚持使用 redis 存储,因为它是 github 上最受欢迎的存储之一。

【讨论】:

以上是关于Redis Pub/Sub 聊天室的主要内容,如果未能解决你的问题,请参考以下文章

基于NKN的分布式Pub / Sub服务

redis pub/sub 与 node.js 中的 socket.io

为啥 Redis 具有 Pub/Sub 功能?

SpringBoot 集成Redis pub/sub

Redis Pub/Sub 发布订阅模式的深度解析与实现消息队列

redis的pub/sub命令