Nodejs socket.io断开后自动重连上,收到的消息就重复了,断几次就会收到多少重复消息,怎么回事?

Nodejs socket.io断开后自动重连上,收到的消息就重复了,断几次就会收到多少重复消息,怎么回事?

socket.io断开后自动重连上,收到的消息就重复了,断几次就会收到多少重复消息,怎么回事?为何不能自动销毁掉。 该如何解决

12 回复

当使用 socket.io 进行实时通信时,如果客户端与服务器之间的连接断开并重新连接,可能会导致消息重复接收的问题。这是因为每次重新连接时,客户端会重新加入所有现有的事件监听器,而这些监听器在之前的连接中已经被注册过。因此,每当有新的消息到达时,每个重新连接的客户端都会触发一次事件处理函数,从而导致消息重复。

解决方案

一种有效的解决方案是在每次重新连接时清除旧的事件监听器,并重新注册它们。这可以通过在事件监听器内部使用 once 方法来实现,once 方法确保事件只被触发一次。

示例代码

const io = require('socket.io')(server, {
    transports: ['polling', 'websocket']
});

io.on('connection', function(socket) {
    console.log('New client connected');

    // 清除旧的事件监听器
    socket.removeAllListeners();

    // 使用 once 方法确保事件只被触发一次
    socket.once('message', function(msg) {
        console.log('Message received:', msg);
        // 处理消息
    });

    // 当客户端断开连接时
    socket.on('disconnect', function() {
        console.log('Client disconnected');
    });
});

解释

  1. 清除旧的事件监听器:通过调用 socket.removeAllListeners(),我们可以确保在每次重新连接时清除所有旧的事件监听器。
  2. 使用 once 方法once 方法用于确保事件只被触发一次。这意味着即使客户端重新连接多次,消息也只会被处理一次。
  3. 处理 disconnect 事件:我们还需要监听 disconnect 事件,以便在客户端断开连接时进行适当的清理工作。

通过这种方式,可以有效避免由于客户端多次重新连接而导致的消息重复问题。


已经搞定 原因: 错误写法: var socket = io.connect(); socket.on(‘connect’, function () { socket.on(‘message’, function(message) { }); socket.on(‘disconnect’, function() { }); }); 正确写法: var socket = io.connect(); socket.on(‘connect’, function () { }); socket.on(‘message’, function(message) { }); socket.on(‘disconnect’, function() { });

thank you~~

楼主的代码是client的吗? 为什么我没写connect和discontect 也会这样呢? 手工discontect重复链接不理想啊!求解救。。

我勒个去,找到问题了 因为之前不知道在哪里看的,加了下面这个代码 socketio.socket.on(‘error’, function(){ socketio.socket.connect(); });

发现IE下此问题还存在 好像在github里看到,说这个是bug,不知道修复没。。。

     socket.on('connect', function () {
        try {
            console.log('connect success');
        } catch (e) {
        }
        var curTime = new Date().getTime();
        Ws.reConnNum = 1;
        if (Ws.lastTime && (curTime - Ws.lastTime <= 5000)) {
            Ws.lastTime = curTime;
            return;
        }
        Ws.lastTime = curTime;
        socket.emit('init', {id:speek.selfid, nation:speek.selfgroup});
    });
    socket.on('message', function (message, callback) {
        try {
            console.log('message');
        } catch (e) {
        }
    });
    socket.on('disconnect', function () {
        try {
            console.log('disconnect');
        } catch (e) {
        }
    });
    socket.on('connect_failed', function () {
        try {
            console.log('connect_failed');
        } catch (e) {
        }
    });
    socket.on('error', function () {
        try {
            console.log('error');
        } catch (e) {
        }
    });
    socket.on('reconnect_failed', function () {
        try {
            console.log('reconnect_failed');
        } catch (e) {
        }
    });
    socket.on('reconnect', function () {
        try {
            console.log('reconnect');
        } catch (e) {
        }
    });
    socket.on('reconnecting', function () {
        if (Ws.reConnNum == 3) {
            setTimeout(function () {
                if (Ws.reConnNum == 4) {
                    Ws.showDisWin();
                }
            }, 5000);
        }
        Ws.reConnNum++;
        try {
            console.log('reconnecting');
        } catch (e) {
        }
    });

我也遇到楼主的问题了,不知道我这样写是否有问题???

谢谢楼主。也是这样解决的。

socket.on('connect', function () {
});

里应该是什么代码

请问这个问题最终怎么解决的,本菜鸟初次用,也遇到这个问题,谢谢各位大神

请问这个问题最终怎么解决的,本菜鸟初次用,也遇到这个问题,谢谢各位大神

在使用 Socket.IO 时,如果客户端与服务器断开连接后重新连接,可能会导致事件监听器多次注册,从而引发重复接收消息的问题。这是因为每次连接成功后,都会重新绑定事件监听器,而之前的监听器并未被销毁。

解决方法

为了解决这个问题,我们需要确保在重新连接之前移除所有旧的事件监听器。可以通过以下几种方式实现:

  1. 在每次重新连接前清除事件监听器
    • 可以通过一个标志位来检查是否已经绑定过监听器,在绑定之前检查该标志位。
    • 或者在断开连接时清除事件监听器。

示例代码

const io = require('socket.io')(server);

let isListenerBound = false;

function bindListeners(socket) {
    if (isListenerBound) return;
    
    socket.on('message', (data) => {
        console.log('Received:', data);
    });

    isListenerBound = true;
}

io.on('connection', (socket) => {
    console.log('A user connected');
    
    bindListeners(socket);

    socket.on('disconnect', () => {
        console.log('User disconnected');
        isListenerBound = false; // 在断开连接时重置标志位
    });
});

在这个示例中,我们使用了一个 isListenerBound 变量来追踪是否已经绑定了监听器。当客户端连接时,我们检查这个变量,如果未绑定,则绑定事件监听器,并将标志位置为 true。当客户端断开连接时,我们将标志位置为 false,这样下次连接时可以重新绑定监听器。

总结

通过这种方式,我们可以避免在客户端断开连接并重新连接后多次接收消息的问题。这种方法简单有效,适用于大多数场景。

回到顶部