django - Redis + Node.js + Socket.io + Django/Celery 设置中的奇怪行为。断开连接的套接字仍然接收消息

标签 django node.js redis socket.io celery

我遇到了一个奇怪的问题,我自己无法解决。我建立了一个设置,通过 Django/Celery 周期性任务发送 JSON 序列化消息。此任务通过 Redis 与 node.js 服务器通信。 Node.js 通过 socket.io 处理与网络浏览器的通信。

Django/Celery 任务

@periodic_task(run_every=crontab()) # every minute
def process_channels():
     r = redis.StrictRedis(host='localhost', port=6379, db=0)

     for i in xrange(1,21): # 1..20
         data_dict = {}
         data_dict['time'] = time.ctime(time.time())
         data_dict['message'] = os.urandom(10).encode('hex')
         r.publish('channel', json.dumps(data_dict) )
         time.sleep(2)

node.js 服务器

var http = require('http');
var server = http.createServer().listen(4000);
var io = require('socket.io').listen(server);
var querystring = require('querystring')
var redis = require('socket.io/node_modules/redis');
var sub = redis.createClient();

sub.subscribe('channel');

io.sockets.on('connection', function (socket) {
    // grab message from Redis and send to client
    sub.on('message', function(channel, message) {
        console.log(message + ' ' + channel + ' ' + socket.id);
        socket.send(message);
    });

    socket.on('disconnect', function() {
         console.log('disconnected')
    });
});

index.html

$(document).ready(
    function() {
         var socket = io.connect('localhost', {
              port: 4000
         });

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

         socket.on('message', function(message) {
             // deserialize message from DJANGO
             var data = JSON.parse(message);

             //Append message to the bottom of the list
             $('#comments').append('Time: ' + data.time + '<br />');
             $('#comments').append('Message: ' + data.message + '<br /><br />');
          } });
     });

很简单。任务通过 Redis 将随机生成的消息发送到 Node 服务器,然后再将消息发送到浏览器。如您所见,我正在 Node 服务器中记录消息和 socket.id。

在我重新加载页面之前,一切都按预期工作。当我第一次加载页面时,服务器控制台会打印类似这样的内容:

{"message": "85105676e21512a33e72", "time": "Fri Oct 18 22:33:10 2013"} channel 94k39P2j9dMv1JEZRW6Q

当我重新加载页面时,会出现:

disconnected
{"message": "c3e93646d60a5a6727f6", "time": "Fri Oct 18 22:33:18 2013"} channel 94k39P2j9dMv1JEZRW6Q
{"message": "c3e93646d60a5a6727f6", "time": "Fri Oct 18 22:33:18 2013"} channel wJwsRvpgEks7g1AURW6R

同一条消息被发送了两次。每次我重新加载页面时,都会再发送一次消息。查看 socket.ids(第 3 个字段),似乎套接字在重新加载之前未正确断开连接,服务器仍在通过该套接字发送消息。我不明白这种行为。调用了“断开连接”方法,因此应该以任何方式对其进行处理。有人可以帮帮我吗?

非常感谢。

最佳答案

在客户端尝试使用 socket.once() 而不是 socket.on()。

socket.once('message', function() {
   ...
}

问题可能是每次重新加载页面时,都会附加多个监听器。我遇到了类似的问题,“.once()”是我能找到的唯一解决方案。

如果这没有帮助,您可以尝试探索此处发布的类似问题。希望能帮助到你 :) https://github.com/LearnBoost/socket.io/issues/997

关于django - Redis + Node.js + Socket.io + Django/Celery 设置中的奇怪行为。断开连接的套接字仍然接收消息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19458908/

相关文章:

redis - 是否必须同时满足条件 'seconds' 和 'key modification' 才能使快照工作 - Redis

json - 在服务器端缓存 JSON 对象

python - Django 模板标签创建空间

node.js - NodeJS : Force user to refresh session after permissions have been changed by another user

javascript - 将浏览器作为终端进程运行

javascript - 生成子 Node 进程并将其通过管道传输到当前 Node 进程有什么用?

redis - 如何通过它的索引访问键?

html - 在 Chrome PDF 查看器中加载时 PDF 链接卡住

django - 如何删除表单字段标签中的 django-filter 附加关键字

python - 使用 django 应用程序从 MySQL 中的现有表中检索数据