当“重新”连接到socket.io时,Node.js + socket.io + node-amqp和queue binginds

时间:2011-09-29 03:07:09

标签: rabbitmq socket.io amqp

我有一个非常接近这个样本的场景:

一个主屏幕:

  • 此屏幕(客户端)将通过服务器连接到socket.io服务器:9090 / scope(io.connect(“http:// server:9090 / scope))并将发送一个事件”userBindOk “(socket.emit(”userBindOk“,message))到socket.io服务器;

  • 服务器接收连接和“userBindOk”。此时,服务器应该获得与rabbitmq服务器的活动连接,并将队列绑定到刚刚通过socket.io连接到应用程序的相应用户。样品:

    socket.on(“connection”,function(client){     //客户端ID是1234    //绑定rabbitmq交换,队列和:    queue.subscribe(//接收回调); })

  • 到目前为止,没问题 - 我可以通过socket.io发送/接收消息而不会出现问题。

  • 但是,如果我刷新页面,所有这些步骤将再次完成。因此,将发生与队列的绑定,但这次与socket.io客户端的另一个会话有关。这意味着如果我向与第一个socket.io会话相关的队列发送消息(在页面刷新之前),那个绑定应该(我认为)接收消息并将其发送到无效的socket.io客户端(页面)在socket.io上下文中刷新= new client.id)。我可以证明这种行为,因为每次刷新页面时我都需要发送x次以上的消息。例如:我第一次连接: - 所以,1条消息 - 一次屏幕更新;刷新页面:我需要向队列发送2条消息,只有第二条消息将从“实际”socket.io客户端会话中收到 - 这种行为将发生在我刷新页面的数量上(20页刷新,20条消息)要发送到队列并且服务器socket.io“last”客户端将消息发送到客户端socket.io以呈现到屏幕中。

我认为的解决方案是:

  • 找到一种在与socket.io服务器断开连接时“取消绑定”队列的方法 - 我还没有在node-amqp api上看到这个选项(等待它:D)

    < / LI>
  • 找到一种方法,使用相同的client.id重新连接socket.io客户端。通过这种方式,我可以识别即将到来的客户端并应用一些逻辑来缓存套接字。

有什么想法吗?我试图非常清楚......但是,正如你所知,在试图澄清某些特定于某些背景的东西时,揭露你的问题并不是那么真实......

TKS

1 个答案:

答案 0 :(得分:1)

我解决了这个问题:

我曾经将rabbitMq队列声明为durable = true,autoDelete = false,exclusive = false并且在我的应用程序中有1个队列/用户和1个交换(type = direct),其中包含routing_key name = queueName,我的应用程序也是使用队列为其他客户端不同的浏览器,如Android app或iphone app作为推送后备,所以我使用crear 1队列为earch用户。

此问题的解决方案是更改我的rabbitMQ队列和交换声明。现在我将exchange / user声明为fanout并且autoDelete = True,并且用户将拥有N个队列,其中duration = true,autoDelete = true,exclusive = true(编号队列=编号客户端)并且所有队列都绑定到用户交换(多播)。

注意:我的应用程序在django中是wirten,我使用node + socket + amqp能够使用web.scokets与浏览器通信,所以我使用node-restler查询我的app api以获取用户队列资讯

那就是rabbitMQ方面,对于节点+ amqp + socket,我这样做了:

服务器端:

  • onConnect:用户交换声明为扇出,autoDelete,持久。然后将队列声明为持久,autodelete和exclusive,然后queue.bind到用户交换,最后是queue.subscribe和socket.disconnect将销毁队列,因此当客户端连接应用程序时将存在队列这解决了刷新的问题,并允许用户使用app具有多个窗口选项卡:

服务器端:

            /*
             * unCaught exception handler
             */

            process.on('uncaughtException', function (err) {
                sys.p('Caught exception: ' + err);
                global.connection.end();
            });


            /*
             * Requiere libraries
             */

            global.sys =  require('sys');
            global.amqp = require('amqp');
            var rest = require('restler');
            var io = require('socket.io').listen(8080);

            /*
             * Module global variables
             */
            global.amqpReady = 0;


            /*
             * RabbitMQ connection
             */

            global.connection = global.amqp.createConnection({
                             host: host,
                             login: adminuser,
                             password: adminpassword,
                             vhost: vhost
                            });

            global.connection.addListener('ready', 
                        function () {
                            sys.p("RabbitMQ connection stablished");
                            global.amqpReady = 1;
                        }
            );


            /*
             * Web-Socket declaration
             */ 

            io.sockets.on('connection', function (socket) {
                socket.on('message', function (data) {
                    sys.p(data);
                    try{
                        var message = JSON.parse(data);                 
                    }catch(error){
                        socket.emit("message", JSON.stringify({"error": "invalid_params", "code": 400}));
                        var message = {};
                    }           
                    var message = JSON.parse(data);
                    if(message.token != undefined) {

                      rest.get("http://dev.kinkajougames.com/api/push",
                                {headers: 
                                    {
                                        "x-geochat-auth-token": message.token 
                                    }
                                }).on('complete', 
                                    function(data) {
                                        a = data;
                                }).on('success',
                                    function (data){
                                        sys.p(data);
                                        try{                                
                                            sys.p("---- creating exchange");
                                            socket.exchange = global.connection.exchange(data.data.bind, {type: 'fanout', durable: true, autoDelete: true});
                                            sys.p("---- declarando queue");
                                            socket.q = global.connection.queue(data.data.queue, {durable: true, autoDelete: true, exclusive: false},
                                                function (){
                                                    sys.p("---- bind queue to exchange");
                                                    //socket.q.bind(socket.exchange, "*");
                                                    socket.q.bind(socket.exchange, "*");
                                                    sys.p("---- subscribing queue exchange");
                                                    socket.q.subscribe(function (message) {
                                                        socket.emit("message", message.data.toString());
                                                    });     
                                                }
                                            );
                                        }catch(err){
                                            sys.p("Imposible to connection to rabbitMQ-server");
                                        }                                   

                                }).on('error', function (data){
                                    a = {
                                        data: data,
                                    };
                                }).on('400', function() {
                                    socket.emit("message", JSON.stringify({"error": "connection_error", "code": 400}));
                                }).on('401', function() {
                                    socket.emit("message", JSON.stringify({"error": "invalid_token", "code": 401}));
                                });               
                    }
                    else {
                      socket.emit("message", JSON.stringify({"error": "invalid_token", "code": 401}));
                    }

                });
                socket.on('disconnect', function () {
                    socket.q.destroy(); 
                    sys.p("closing socket");
                });
            });

客户端:

  • 使用选项'强制新连接'= true并且'卸载时同步断开'的套接字intance = =。
  • 客户端使用onbeforeunload和onunload windows对象事件发送socket.disconnect
  • socket.connect事件上的客户端将用户令牌发送到节点。
  • 来自套接字的处理消息

            var socket;
            function webSocket(){
                //var socket = new io.Socket();
                socket = io.connect("ws.dev.kinkajougames.com", {'force new connection':true, 'sync disconnect on unload': false});
                //socket.connect();
    
                onSocketConnect = function(){
                    alert('Connected');
                    socket.send(JSON.stringify({
                        token: Get_Cookie('liveScoopToken')
                    }));
                };
    
                socket.on('connect', onSocketConnect);
                socket.on('message', function(data){
                    message = JSON.parse(data);
                    if (message.action == "chat") {
                        if (idList[message.data.sender] != undefined) {
                            chatboxManager.dispatch(message.data.sender, {
                                first_name: message.data.sender
                            }, message.data.message);
                        }
                        else {
                            var username = message.data.sender;
                            Data.Collections.Chats.add({
                                id: username,
                                title: username,
                                user: username,
                                desc: "Chat",
                                first_name: username,
                                last_name: ""
                            });
                            idList[message.data.sender] = message.data.sender;
                            chatboxManager.addBox(message.data.sender, {
                                title: username,
                                user: username,
                                desc: "Chat",
                                first_name: username,
                                last_name: "",
                                boxClosed: function(id){
                                    alert("closing");
                                }
                            });
                            chatboxManager.dispatch(message.data.sender, {
                                first_name: message.data.sender
                            }, message.data.message);
                        }
                    }
                });
            }                           
    
            webSocket();
    
            window.onbeforeunload = function() {
                return "You have made unsaved changes. Would you still like to leave this page?";
            }
    
            window.onunload = function (){
                socket.disconnect();
            }
    

就是这样,所以不再对信息进行整理。