7

我需要为我的应用程序(Ruby On Rails)添加实时,所以,我认为更好的方法是使用 node.js + socket.io + redis。

我在后端有这个 application.js 文件(node.js)

var app = require('http').createServer();
var io = require('socket.io');
var redis = require('redis').createClient();
var _ = require('underscore')._;

io = io.listen(app);
io.configure(function() {
    io.set("transports", ["xhr-polling"]);
    io.set("polling duration", 10);
    io.set("close timeout", 10);
    io.set("log level", 1);
})

redis.subscribe('rt-change');

io.on('connection', function(socket) {
    redis.on('message', function(channel, message) {
        socket.emit('rt-change', message)
    });
});

var port = process.env.PORT || 5001;
app.listen(port);

和messages.js在前端

 var socket = io.connect('http://localhost:5001/socket.io');
socket.on('rt-change', function (data) {
    console.log(data);
});

我正在使用node application.js命令启动 application.js 并且它有效!

MacBook-Pro-Zhirayr:rt zhirayr$ node application.js info - socket.io 启动

但是当我尝试从 Rails 应用程序使用 redis ($redis.publish 'rt-change', {hello:'world'}) 发送消息时,我的浏览器不会在控制台中记录任何内容。我敢肯定,建立了来自浏览器的连接,因为当我停止节点时,它会引发连接被拒绝错误。而且我确定 redis 和节点之间的连接已建立,导致 application.js 中的 console.log(message) 记录它。但是浏览器中的 console.log 不会记录任何内容。

任何想法为什么?

谢谢。

#Antoine 的 UPD

在 application.js 中添加了 console.log io.on('connection', function(socket) { redis.on('message', function(channel, message) { console.log('new message from redis'); socket.发射('rt-change', 消息); }); });

当 r.publish 'rt-change', {:hello=>'world'} 被执行时,节点记录如下:

new message from redis
new message from redis
new message from redis
new message from redis
new message from redis
new message from redis
new message from redis
new message from redis
new message from redis
new message from redis
new message from redis

奇怪的是,节点为 1 条消息记录了 11 次。

4

2 回答 2

11
 var socket = io.connect('http://localhost:5001/socket.io');
socket.on('rt-change', function (data) {
    console.log(data);
});

这部分代码似乎不正确,根据http://socket.io上的文档,您应该执行以下操作:

<script src="http://localhost:5001/socket.io/socket.io.js"></script>
<script>
  var socket = io.connect('http://localhost:5001');
</script>
于 2013-06-06T17:30:44.850 回答
5

您为单个发布获得多次执行的原因是代码中的嵌套事件处理。我将尽可能简单地解释这一点。

你打电话时

io.on('connection', function(socket) {...});

您侦听connection事件并将给定的函数添加为事件处理程序。每当有新用户连接时就会执行它。这为每次执行处理程序创建了一个单独的范围。

当你调用这个

io.on('connection', function(socket) {
    redis.on('message', function(channel, message) {
        console.log('new message from redis');
        socket.emit('rt-change', message);
    });
});

message您分别为每个连接的用户添加 redis 订阅者事件的侦听器。这就是为什么您会获得多个日志并且连接的用户会获得同一消息的多个副本。您收到 11 条消息,这意味着当时有 11 个不同的用户连接。

要解决此问题,您可以调用once而不是on监听事件。像这样

io.once('connection', function(socket) {
    redis.on('message', function(channel, message) {
        console.log('new message from redis');
        socket.emit('rt-change', message);
    });
});

这也适用于 socket.io 客户端。请参阅我以前的答案以明确这一点:

  1. socket.io 代码结构:在哪里放置方法?
  2. socket.io 重新连接后再创建一个连接
于 2013-06-08T15:11:17.990 回答