【问题标题】:Express + Socket.IO + RabbitMQ (node-amqp)Express + Socket.IO + RabbitMQ (node-amqp)
【发布时间】:2012-10-25 15:14:39
【问题描述】:

我很难将这三个放在一起,可能是因为我没有正确理解 Express 路由的概念。

我有一个带有事件更新的 RabbitMQ 队列。我们可以通过它们的 id 来识别这些事件。所以我想在一个给定的页面上看到一个事件,只是对应于它的 id 的更新。

队列:1316, 1539, 3486, 3479, 1316, 3890, 3479, ... -> 无限期地从数据库馈送。 www.example.com/event/1316 -> 从队列中获取 id 为 1316 的消息 www.example.com/event/3479 -> 从队列中获取 id 为 3479 的消息

当我加载第一个事件时,我的代码运行良好,但是当我在不同的窗口中加载第二个事件时,它会从两个事件中获取消息,如果我加载第三个事件,猜对了,它会从三个事件中获取消息身份证。

app.js

var express = require('express')  
, http = require('http');
var app = express();
var server = http.createServer(app);
var io = require('socket.io').listen(server, { log: false });
require('./io')(io);

var amqp = require('amqp');
var rabbitMQ = amqp.createConnection({ host: 'localhost' });

rabbitMQ.on('ready', function() {
  console.log('Connected to RabbitMQ');
  io.sockets.on('connection', function (socket) {
    console.log('Socket connected: ' + socket.id);
    rabbitMQ.queue('offer', { autoDelete: false, durable: false, exclusive: false }, function(q) {    
      q.bind('#'); // Catch all messages    
      q.subscribe(function (message) {
        obj = JSON.parse(message.data.toString());
        //socket.broadcast.to(obj.id).emit('message', obj);
        io.sockets.in(obj.id).emit('message', obj);
      });
    });
  });
});

var routes = require('./routes')
, event = require('./routes/event');

app.get('/', routes.index);
app.get('/event/:id', event.index);

server.listen(app.get('port'), function(){
  console.log("Express server listening on port " + app.get('port'));
});

io.js

var socketio = function (io) { 
  if (!io) return socketio._io;  
  socketio._io = io;
} 

module.exports = socketio;

routes/event.js

var io = require('../io')();

exports.index = function(req, res) {
  io.sockets.on('connection', function (socket) {
    socket.join(req.params.id);
  });
  res.render('event', { title: 'Event' });
};

谢谢!

【问题讨论】:

    标签: node.js express socket.io rabbitmq amqp


    【解决方案1】:

    你收到它们都是因为你join 但从来没有leave 房间。如果您从 wiki 查看 Socket IO Rooms,在底部,它提供 io.sockets.manager.roomClients[socket.id] 作为获取套接字已加入的房间列表的一种方式(如果您访问了所有三个链接,我怀疑这将包括所有三个)。

    您可能想尝试浏览此房间列表和leave 任何不是当前房间的房间,看看是否能解决问题。

    编辑

    好的,所以,有两个原因/解决方案。我刚刚测试了我的理论,它是有效的——你会收到joined 的每个房间的消息,并且会继续这样做,直到你 leave 他们。所以这里是选项:

    1。 leave所有其他房间当他们join一个房间

    io.sockets.on('connection', function (socket) {
        var room = req.params.id;
    
        var roomKeys = Object.keys(io.sockets.manager.roomClients[socket.id]);
        roomKeys.forEach(function(key) {
            if (key === '' || key === '/' + room) return;
            socket.leave(key.slice(1));
        });
    
        socket.join(room);
    });
    

    如前所述,我对此进行了测试。它有效。

    2。不要发送message 事件,发送{room name} 事件

    您可以发出“{房间名称}”事件,而不是发出“消息”事件。而不是包含io.sockets.in(obj.id).emit('message', obj);q.subscribe() 回调,您只需执行socket.emit(obj.id, obj); 并且您将让javascript 客户端仅侦听该页面的事件类型(基于URL 路径)。

    我也对此进行了测试。它也有效。它也更简单(我认为),因为它只需要在您的 q.subscribe() 回调中使用 .emit(),这意味着您可以保存“房间管理”的内容。

    【讨论】:

    • 但我不想离开房间。我想要的是对于每个活动页面,都有一个带有 id 的房间,我可以在其中广播包含该 id 的所有消息。
    • 我相信虽然您连接的客户正在加入他们访问的每个房间,但在他们离开页面时并没有取消加入,所以转到 /event/1234 然后 /event/2345 意味着他们加入了两个房间,因此他们将两个提要都发送到浏览器 - 这就是您所看到的,对吧?
    • 所以现在我更加迷茫了。假设我想在五个不同的窗口中有五个事件。据我了解,他们每个人都会创建一个新套接字。我想要的是每个套接字都有一个不同的房间(或另一个解决方案),因为在事件页面上我只想获取与其 ID 对应的事件更新。所以我不明白为什么当我加载第二个窗口时,这个套接字也订阅了第一个 id。
    • 所有/event/nnnn 页面都使用同一个套接字。当您从一个页面切换到另一个页面时,您仍然在同一个插座上,因此您仍然连接到您之前使用该插座加入的任何房间。因此,当您致电 .join() 加入新房间时,它会添加新房间 - 但您仍然是前一个房间的成员,因此您仍然会收到这些消息。因为都是同一个socket,所以离开一页并不意味着离开一个房间。是不是更清楚了?
    • 但是我将每个事件加载到不同的窗口上同时打开了几个,我可以在服务器中看到这些套接字具有不同的 ID。
    【解决方案2】:

    在尝试和失败之后,我明白我做错了什么,因为在路由器内部使用io.sockets.on('connection') 正在复制事件。所以归根结底,最简单的思维方式是正确的。

    app.js

    var room = '';
    var roomHandler = function(req, res, next) {
      if (req.path.match('event')) {
        room = req.params.id;
      } 
      next(); // Passing the request to the next handler in the stack.
    }
    
    io.sockets.on('connection', function (socket) {    
      socket.join(room);
    });
    
    rabbitMQ.on('ready', function() { 
      rabbitMQ.queue('offer', { autoDelete: false, durable: false, exclusive: false }, function(q) {      
        q.bind('#'); // Catch all messages  
        q.subscribe(function (message) {
          obj = JSON.parse(message.data.toString());
          io.sockets.in(obj.id).emit('message', obj);
        });
      });
    });
    
    app.get('/', routes.index);
    app.get('/event/:id', roomHandler, event.index);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-05-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-07
      • 2011-11-27
      • 1970-01-01
      • 2013-02-15
      相关资源
      最近更新 更多