socket.io:没有触发断开事件

Posted

技术标签:

【中文标题】socket.io:没有触发断开事件【英文标题】:socket.io: disconnect event isn't fired 【发布时间】:2012-05-07 17:23:23 【问题描述】:

我做了一个简单的实时访客计数器。

您可以从this repository下载。

服务器上的断开连接事件(即使在浏览器关闭后)永远不会被触发。

server.js 是:

(function () 
var app, count, express, io;

express = require('express');
io = require('socket.io');

app = module.exports = express.createServer();

app.configure(function () 
    app.set('views', __dirname + '/views');
    app.set('view engine', 'jade');
    app.use(express.bodyParser());
    app.use(express.methodOverride());
    app.use(require('stylus').middleware(
        src: __dirname + '/public'
    ));
    app.use(app.router);
    return app.use(express.static(__dirname + '/public'));
);

app.configure('development', function () 
    return app.use(express.errorHandler(
        dumpExceptions: true,
        showStack: true
    ));
);
app.configure('production', function () 
    return app.use(express.errorHandler());
);

io = require('socket.io').listen(app);

count = 0;

io.sockets.on('connection', function (socket) 
    count++;
    io.sockets.emit('count', 
        number: count
    );
);

io.sockets.on('disconnect', function () 
    console.log('DISCONNESSO!!! ');
    count--;
    io.sockets.emit('count', 
        number: count
    );
);


app.get('/', function (req, res) 
    return res.render('index', 
        title: 'node.js express socket.io counter'
    );
);
if (!module.parent) 
    app.listen(10927);
    console.log("Express server listening on port %d", app.address().port);


).call(this);

客户端上的脚本是:

    script(type='text/javascript')

        var socket = io.connect();

        socket.on('count', function (data) 
            $('#count').html( data.number );
        );

【问题讨论】:

【参考方案1】:

将您的断开连接代码放在您的连接块中,然后像这样编辑它:

io.sockets.on('connection', function (socket) 
    count++;
    io.sockets.emit('count', 
        number: count
    );

    socket.on('disconnect', function () 
        console.log('DISCONNESSO!!! ');
        count--;
        io.sockets.emit('count', 
            number: count
        );
    );
);

通过这种方式,您可以检测特定套接字(特别是传递给在连接上运行的匿名函数的套接字)何时断开。

【讨论】:

你注意到我上面写了socket.on吗? 仅供参考,如果 xhr-polling 用于传输,则在断开连接之前可能会有相当长的延迟。 XHR-Polling 是否也会影响连接事件? 正如@NoNameProvided 提到的,断开连接事件应该使用once 而不是on【参考方案2】:

从 Socket.IO 1.0io.engine.clientsCount 属性可用。此属性告诉您您的应用当前有多少打开的连接。

io.sockets.on('connection', function (socket) 
    io.sockets.emit('count', 
        number: io.engine.clientsCount
    );

    socket.once('disconnect', function () 
        io.sockets.emit('count', 
            number: io.engine.clientsCount
        );
    );
);

注意:使用.once而不是.on,监听器将自动从socket中移除,这对我们现在有好处,因为每个套接字只触发一次disconnect事件。

【讨论】:

【参考方案3】:

以防万一其他人犯了这个愚蠢的错误:确保您定义的任何套接字中间件最后调用next(),否则不会运行其他套接字处理程序。

// make sure to call next() at the end or...
io.use(function (socket, next) 
    console.log(socket.id, "connection middleware");
    next(); // don't forget this!
);

// ...none of the following will run:

io.use(function (socket, next) 
    console.log(socket.id, "second middleware");
    next(); // don't forget this either!
);

io.on("connection", function (socket) 
    console.log(socket.id, "connection event");
    socket.once("disconnect", function () 
        console.log(socket.id, "disconnected");
    );
);

【讨论】:

这个 next() 真的花了我几个小时才找到。这是我在套接字断开连接后立即执行操作所需的。应该更明显。

以上是关于socket.io:没有触发断开事件的主要内容,如果未能解决你的问题,请参考以下文章

如何在用户从帐户注销时断开事件触发(node.js + express socket.io)

Socket.IO处理断开事件

Socket.io 睡眠一些客户端

Socket.io 断开事件和相关闭包的垃圾收集

如何从 socket.io 获取原生事件数组?

如何在socket.io中的断开事件上获取断开连接的客户端的套接字ID