node.js + socket.io + redis + rails - 实时应用程序

Mar*_*sov 7 javascript node.js socket.io

我需要在我的应用程序(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);
Run Code Online (Sandbox Code Playgroud)

和前端的messages.js

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

我正在使用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和node之间的连接已建立,导致application.js中的console.log(message)记录它.但是浏览器中的console.log不会记录任何内容.

有什么想法吗?

谢谢.

UPD for #Antoine

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

当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
Run Code Online (Sandbox Code Playgroud)

奇怪的是,1个消息的节点记录11次.

Ant*_*ine 11

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

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

<script src="http://localhost:5001/socket.io/socket.io.js"></script>
<script>
  var socket = io.connect('http://localhost:5001');
</script>
Run Code Online (Sandbox Code Playgroud)


use*_*109 5

您为单个发布获得多次执行的原因是您的代码中嵌套的事件处理.我会尽力解释这个问题.

你打电话的时候

io.on('connection', function(socket) {...});
Run Code Online (Sandbox Code Playgroud)

你监听connection事件并将给定的函数添加为事件处理程序.只要新用户连接,就会执行它.这为每次执行处理程序创建了一个单独的范围.

当你打电话给这个

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

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);
    });
});
Run Code Online (Sandbox Code Playgroud)

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

  1. socket.io代码结构:放置方法的位置?
  2. socket.io在重新连接后再创建一个连接