web-dev-qa-db-ja.com

Socket.ioを介してRedisをPubSubとして使用する

ユーザーがプライベートチャットやグループチャットを行えるようにするチャットアプリケーションを作成しています。このアプリで次のテクノロジーを使用する計画:-

NodeJs + Socket.io + Redis + CouchDB(メッセージ履歴を保存するため)+ AngularJS

RedisをPubSubサービスとして使用する私の最初の調査によると、Socket.ioをpub-subとして使用するよりも優れたアプローチです。この理由は、異なるユーザーが異なるサーバーインスタンスに接続されている場合、このシナリオでソケットを使用すると、ユーザー1はユーザー2に渡されません(ユーザー1はサーバー1に接続され、ユーザー2はサーバー2に接続されます)。

しかし、Redisを使用する場合、私が理解しているように、プライベートチャットを有効にするために新しいチャネルを作成する必要があります。そして、Redisでの10kチャネルの制限です。

私の疑問は

  1. 2人のユーザー間のプライベートチャットを有効にするために、毎回新しいチャネルを作成する必要がありますか?
  2. 個別のチャネルを作成する必要がある場合、実際には10Kチャネルの制限はありますか?
  3. プライベートチャットを有効にするために、Sockets.ioでRedisをpub/subとして使用する実際の例が必要です。

よろしく、ビクラム

14
VikramK

以下の記事/ブログ投稿を読んだ後、socket.io pub/subでpub/subにRedisを使用すると、スケーラビリティとパフォーマンスの向上に役立ちます。

https://github.com/sayar/RedisMVA/blob/master/module6_redis_pubsub/README.md

https://github.com/rajaraodv/redispubsub

さらに、redisを使用してプライベートチャットでクイックPOCを作成できます。これがコードです:-

var app = require('http').createServer(handler);
app.listen(8088);
var io = require('socket.io').listen(app);
var redis = require('redis');
var redis2 = require('socket.io-redis');
io.adapter(redis2({ Host: 'localhost', port: 6379 }));
var fs = require('fs');

function handler(req,res){
    fs.readFile(__dirname + '/index.html', function(err,data){
        if(err){
            res.writeHead(500);
            return res.end('Error loading index.html');
        }
        res.writeHead(200);
        console.log("Listening on port 8088");
        res.end(data);
    });
}

var store = redis.createClient();   
var pub = redis.createClient();
var sub = redis.createClient();
sub.on("message", function (channel, data) {
        data = JSON.parse(data);
        console.log("Inside Redis_Sub: data from channel " + channel + ": " + (data.sendType));
        if (parseInt("sendToSelf".localeCompare(data.sendType)) === 0) {
             io.emit(data.method, data.data);
        }else if (parseInt("sendToAllConnectedClients".localeCompare(data.sendType)) === 0) {
             io.sockets.emit(data.method, data.data);
        }else if (parseInt("sendToAllClientsInRoom".localeCompare(data.sendType)) === 0) {
            io.sockets.in(channel).emit(data.method, data.data);
        }       

    });

io.sockets.on('connection', function (socket) {

    sub.on("subscribe", function(channel, count) {
        console.log("Subscribed to " + channel + ". Now subscribed to " + count + " channel(s).");
    });

    socket.on("setUsername", function (data) {
        console.log("Got 'setUsername' from client, " + JSON.stringify(data));
        var reply = JSON.stringify({
                method: 'message',
                sendType: 'sendToSelf',
                data: "You are now online"
            });     
    });

    socket.on("createRoom", function (data) {
        console.log("Got 'createRoom' from client , " + JSON.stringify(data));
        sub.subscribe(data.room);
        socket.join(data.room);     

        var reply = JSON.stringify({
                method: 'message', 
                sendType: 'sendToSelf',
                data: "Share this room name with others to Join:" + data.room
            });
        pub.publish(data.room,reply);


    });
    socket.on("joinRooom", function (data) {
        console.log("Got 'joinRooom' from client , " + JSON.stringify(data));
        sub.subscribe(data.room);
        socket.join(data.room);     

    });
    socket.on("sendMessage", function (data) {
        console.log("Got 'sendMessage' from client , " + JSON.stringify(data));
        var reply = JSON.stringify({
                method: 'message', 
                sendType: 'sendToAllClientsInRoom',
                data: data.user + ":" + data.msg 
            });
        pub.publish(data.room,reply);

    });

    socket.on('disconnect', function () {
        sub.quit();
        pub.publish("chatting","User is disconnected :" + socket.id);
    });

  });

HTMLコード

<html>
<head>
    <title>Socket and Redis in Node.js</title>
    <script src="/socket.io/socket.io.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
</head>
<body>
<div id="username">
    <input type="text" name="usernameTxt" /> 
    <input type="button" name="setUsername" value="Set Username" />
</div>
<div id="createroom" style="display:none;">>
    <input type="text" name="roomNameTxt" /> 
    <input type="button" name="setRooomName" value="Set Room Name" />
    <input type="button" name="joinRooomName" value="Join" />
</div>
<div id="sendChat" style="display:none;">
    <input type="text" name="chatTxt" /> 
    <input type="button" name="sendBtn" value="Send" />
</div>
<br />
<div id="content"></div>
<script>    
    $(document).ready(function() {
        var username = "anonymous";
        var roomname = "anonymous";
        $('input[name=setUsername]').click(function(){
            if($('input[name=usernameTxt]').val() != ""){
                username = $('input[name=usernameTxt]').val();
                //var msg = {type:'setUsername',user:username};
                socket.emit('setUsername',{user:username});
            }
            $('#username').slideUp("slow",function(){
                $('#createroom').slideDown("slow");
            });
        });
        $('input[name=setRooomName]').click(function(){
            if($('input[name=roomNameTxt]').val() != ""){
                roomname = $('input[name=roomNameTxt]').val();
                socket.emit('createRoom',{user:username,room:roomname});
            }
            $('#createroom').slideUp("slow",function(){
                $('#sendChat').slideDown("slow");
            });
        });
        $('input[name=joinRooomName]').click(function(){
            if($('input[name=roomNameTxt]').val() != ""){
                roomname = $('input[name=roomNameTxt]').val();
                socket.emit('joinRooom',{room:roomname});
            }
            $('#createroom').slideUp("slow",function(){
                $('#sendChat').slideDown("slow");
            });
        });

        var socket = new io.connect('http://localhost:8088');
        var content = $('#content');

        socket.on('connect', function() {
            console.log("Connected");
        });

        socket.on('message', function(message){
            //alert('received msg=' + message);
            content.append(message + '<br />');
        }) ;

        socket.on('disconnect', function() {
            console.log('disconnected');
            content.html("<b>Disconnected!</b>");
        });

        $("input[name=sendBtn]").click(function(){
            var msg = {user:username,room:roomname,msg:$("input[name=chatTxt]").val()}
            socket.emit('sendMessage',msg);
            $("input[name=chatTxt]").val("");
        });
    });
</script>
</body>
</html>
19
VikramK

これがすべてのコードの基本的なredis pub/subです。

var redis = require("redis");

var pub = redis.createClient();
var sub = redis.createClient();

sub.on("subscribe", function(channel, count) {
    console.log("Subscribed to " + channel + ". Now subscribed to " + count + " channel(s).");
});

sub.on("message", function(channel, message) {
    console.log("Message from channel " + channel + ": " + message);
});

sub.subscribe("tungns");

setInterval(function() {
    var no = Math.floor(Math.random() * 100);
    pub.publish('tungns', 'Generated Chat random no ' + no);
}, 5000);
3
anonystick

足を濡らして簡単なチャットアプリケーションを作成する必要がある場合は、次の開発スタックが非常にうまく連携します。

  • Express.js(Node.js)
  • Redis
  • Socket.IO

アプリケーションは、ユーザーが参加して会話を開始できるチャットルームで構成されています。 Socket.IOは、チャッター数/メッセージが更新され、jQueryを使用してUIで更新されるときに、イベントを発行します。

完全な記事とソースコードについては、次のリンクを確認してください。 https://scalegrid.io/blog/using-redis-with-node-js-and-socket-io/

1
Kunal Nagar

Socket.io-redisさんのコメント:

Socket.io-redisアダプターを使用してsocket.ioを実行することにより、さまざまなプロセスまたはサーバーで複数のsocket.ioインスタンスを実行できます。これらのインスタンスはすべて、相互にイベントをブロードキャストおよび発行できます。したがって、次のコマンドのいずれか:

io.emit('hello', 'to all clients');
io.to('room42').emit('hello', "to all clients in 'room42' room");

io.on('connection', (socket) => {
  socket.broadcast.emit('hello', 'to all clients except sender');
  socket.to('room42').emit('hello', "to all clients in 'room42' room except sender");
});

redis Pub/Subメカニズムを介してクライアントに適切にブロードキャストされます。

そして私は推測します

io.to(socket.id).emit('hello', "to client which has same socket.id");

別のプロセスまたはサーバーでプライベートメッセージを送信します。

ちなみに私はプライベートメッセージも必要なプロジェクトをやっています。他の提案は提起されたいと思います。

1
tingtinghuang