javascript - Socket.io 发送消息两次(或更多)

标签 javascript node.js push-notification socket.io push

我在 node.js 的 server.js 文件中有这段代码:

var app = require('http').createServer(handler), io = require('socket.io').listen(app);
var xml2js = require('xml2js'), parser = new xml2js.Parser(), fs = require('fs');

// creating the server ( localhost:8000 )
app.listen(8000);

/**
 * Esta función es la que envía el archivo js necesario para la comunicación
 * push con sockets
 * 
 * @param req
 * @param res
 */
function handler(req, res) {
    Request = require('url').parse(req.url, true);
    site = Request.query.site;
    entity = Request.query.entity;
    id = Request.query.id;

    fs.readFile(__dirname + '/client.js', 'utf8', function(err, data) {
        if (err) {
            console.log(err);
            res.writeHead(500);
            return res.end('Error loading client.js');
        }
        var dataString = data.toString();
        dataString = dataString.replace('confSite', site);
        dataString = dataString.replace('confEntity', entity);
        dataString = dataString.replace('confId', id);
        res.writeHead(200, {
            'Content-Type' : 'text/javascript;charset=UTF-8'
        });
        res.end(dataString);
    });
};

var listeners = {};
var parsers = {};
var listenersAndSockets = {};
var socketsOnListeners = {};
var watchers = {};
/**
 * Esta función es la que enviará la información que se actualice a los
 * clientes. Escuchará un archivo xml el cual envará al cliente una vez que este
 * haya cambiado
 */
io.sockets.on('connection', function(socket) {
    socket.on ('connect', function() {
        console.log('conectado');
    });
    socket.on('setup', function(config) {
        console.log('setup');
        var site = config.site;
        var entity = config.entity;
        var id = config.id;
        var listenerName = '' + site + entity + id + '';
        watchers[listenerName] = site + '/' + '/' + entity + '/' + id + '.xml';
        socketsOnListeners[socket.id] = listenerName;
        if (typeof socketsOnListeners[listenerName] == 'undefined') {
            socketsOnListeners[listenerName] = {};
        }
        socketsOnListeners[listenerName][socket.id] = socket.id;
        if (typeof listeners[listenerName] == 'undefined') {
            parsers[listenerName] = new xml2js.Parser();
            fs.stat(watchers[listenerName], function(err, stats) {
                if (err) {
                    fs.writeFile(watchers[listenerName], '');
                }
            });
            listeners[listenerName] = function(curr, prev) {
                fs.readFile(watchers[listenerName], function(err, data) {
                    parsers[listenerName].parseString(data);
                });
            };
            fs.watch(watchers[listenerName], listeners[listenerName]);
        }
        parsers[listenerName].addListener('end', function(result,a) {
            socket.volatile.emit('notification', result);
        });
    });

    socket.on('disconnect', function() {
        delete socketsOnListeners[socketsOnListeners[socket.id]][socket.id];
        if (socketsOnListeners[socketsOnListeners[socket.id]].lenght == 0) {
            fs.unwatch(watchers[socketsOnListeners[socket.id]]);
            delete watchers[socketsOnListeners[socket.id]];
        }
        delete socketsOnListeners[socket.id];
    });
});

在我的 test.html 中我有这个:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Prueba de Push</title>
</head>
<body>

    <div id="div1">Este es un texto de prueba</div>

    <script src="http://10.0.0.113:8000/socket.io/socket.io.js"></script>
    <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
    <script src="http://10.0.0.113:8000/?site=levelup&entity=noticia&id=1"></script>

    <script>
        function test(data) {
            console.log(data);
            jQuery('#' + data.id).html(data.content);
        }
    </script>


</body>
</html>

Client.js 是这样的:

var socket = io.connect('http://10.0.0.113:8000');
var config = {
    site : 'confSite',
    entity : 'confEntity',
    id : 'confId'
};

socket.emit("setup", config);
socket.on('reconnect', function() {
    socket.emit("setup", config);
});
// on every message recived we print the new datas inside the #container div
socket.on('notification', function(data) {
    _efbn(data.callback, window, data.response, data);
});

/**
 * Función que ejecuta una función por nombre. Puede usar namespaces
 * (algo.algo.algo.funct)
 * 
 * @see http://stackoverflow.com/questions/359788/javascript-function-name-as-a-string/359910#359910
 */
function _efbn(functionName, context) {
    var args = Array.prototype.slice.call(arguments);
    args = [ args[2], args[3] ]; // Fix para IE.
    var namespaces = functionName.split(".");
    var func = namespaces.pop();
    for ( var i = 0; i < namespaces.length; i++) {
        context = context[namespaces[i]];
    }
    try {
        if (typeof context[func] == 'function') {
            return context[func].apply(this, args);
        }
    } catch (e) {
        console.log(e);
    }
    return null;
}

而在 firefox 中,当我修改服务器上的文件时,我会收到两次或更多次通知。有什么办法可以防止这种情况发生吗?我在 node.js 上阅读了一些关于组的内容...这对我有帮助吗?

最佳答案

您在 setup 事件中开始观看文件。在客户端 setup 事件可能会被发出多次(reconnect 事件)。对于每个 watch 调用,新的监听器将被添加到文件中。您需要检查 watch 监听器在设置之前是否已存在于文件中(对于此套接字)。套接字关闭后,您还需要 unwatch 文件。否则你会发生内存泄漏。

更新

你还需要移动

parser.addListener('end', function(result) {
    socket.volatile.emit('notification', result);
});

setup 事件之外。

关于javascript - Socket.io 发送消息两次(或更多),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12059237/

相关文章:

javascript - CSS Background-Images Loading after HTML Images(涉及Javascript)

javascript - 在nodejs中从客户端发送html到浏览器

java - 当应用程序被杀死时如何停止接收通知?

c# - iOS 平台上的 Xamarin Forms 未收到应用程序中心推送通知

javascript - 上下文菜单事件后未注册 Keyup 事件

javascript - Ajax调用问题

node.js - 邮戳模板 : dynamic variable with html processed as text instead of html

ios - NSInvalidArgumentException - 'Can' t 对 PFObject 上的键或值使用 nil。使用 NSNull 作为值

javascript - 使用下拉列表中选定的值更新 HTML.HiddenFor 值

javascript - 如何仅在开发环境中使用 proxyAgent