Socket.io: Multiple sockets open after reconnect

Created on 28 Jul 2011  ·  54Comments  ·  Source: socketio/socket.io

I've noticed this both on my socket.io application and someone else's. When a reconnect occurs, it's common for more than one socket within a client to be open, which should never happen.

Here's a log I got from my own test application when I had a disconnect/reconnect.

** Disconnect
*
* Reconnecting with delay 1000 Attempts: 1
** Reconnecting with delay 2000 Attempts: 2
*
* Connecting with xhr-polling
** Connecting with xhr-polling
*
* Reconnect with transport type xhr-polling Attempts: 2
** Connected
*
* Connected

When this happens, I get duplicate messages sent, one for each connected socket, even though there should only be one. It is confirmed by Firebug that there are, in fact, two sockets from the client connected. My best guess is that this is in the client code, perhaps not closing the first reconnection attempt.

Of course, the real question might be why was there a disconnect in the first place?

Socket.IO client bug

Most helpful comment

Investigating this a bit further, it seems I found what caused my problems. It's not a bug, but a wrong implementation of the client-side code from my part. facepalm This is what I originally had:

PROBLEM:

var socket = io.connect();

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

  console.log('User connected!');

  socket.on('message', function(message) {

    console.log(message);

  });

});

The above client-side JavaScript caused the multiple calls to console.log() when the client(s) reconnected. This is what I replaced the above with:

SOLUTION:

var socket = io.connect();

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

  console.log('User connected!');

});

socket.on('message', function(message) {

  console.log(message);

});

Now, multiple messages are not being sent back and forth when clients reconnect to the server. Can anybody else confirm that a change of their client-side code fixes the problem?

All 54 comments

The disconnect is fired because technically, the client has disconnected from the server. And is disconnected until the reconnect event is fired again.

But the rest is a bug.

I think this is the reason for a bug in my application as well -

On the server side, I've created a tailable cursor on mongodb to fire every time there's a new insert. This message is then sent via io.sockets.emit() to everyone connected.

But instead of receiving just one message per event, I get multiple repeat messages on the client side.

I'm on an extremely unreliable internet connection, so my guess is that this bug is affecting my code as well.

Were you guys using expressjs? I had this problem with express, rewrote it without and it worked fine.

Express would have absolutely nothing to do with this @mfkp, must have been doing something weird

Agreed with @visionmedia, its a bug in socket.io not with Express. Because the current reconnect implementation was still designed for 0.6, so it's missing some checks and clean ups.

Ah, I see. Nevermind, carry on ;-)

+1 to this. Intermittent issue in our chat app where socket.io opens multiple connections. The client then receives dupes of all emits.

+1. Websockets & chrome. Laptop goes to sleep -> app reconnects after wakup -> double events. Happens only when connecting to remote server. Cant reproduce this locally, must be some reconnect/network latency problem.

is there any workaround to get rid of multiple connection after this?, e.g from client side, if I do socket.disconnect(), will it disconnects all the connections? As I want to avoid multiple updates. does following work?
socket = io.connect(url)
socket.on('connect', function(){
if(multipleConnect) {
socket.disconnect();
socket.removeAllListeners('connect');
io.sockets = {};
socket = io.connect(url);
socket.on('connect', functionToConnect);
}
})

Please, read this https://github.com/LearnBoost/socket.io/issues/474#issuecomment-2833227 .
It explains why this bug occurs and how it can be reproduced.

@3rd-Eden - Any idea where this fix falls on your todo list / priorities? I've got an app that I'm building and I was planning on using this for it, and would love to be able to tell my client that it will reconnect properly from iOS devices. It disconnects after the application is put in the background or device is put to sleep.

Or do you have any idea about how I can code a workaround? I've been working on a few things for the past couple days, but best case always seems to leave too many connections open and drop all of the sockets stored data. The data isn't the end of the world I can use the reconnect trigger from the client to solve that problem, but the concurrent connections is a bit ugly.

Thanks!

@cris I'm not sure that this is the same bug that you mention. I have a very simple example of the bug without a slowdown on the server.

I can clearly reproduce this issue by:

  1. Implement a simple heartbeat client that sends heartbeats on 1 second intervals.
  2. Count the number of new connections server-side.
  3. Count the number of disconnections server-side.
  4. Start the server and make a connection with a client.
  5. Break the network connection between the client and server.
  6. Wait until the server times out and emits a disconnect event.
  7. Reconnect the network connection.

Observe that when the client reconnects it creates 2-4 connections emitting a 'connect' event for each. The server receives 2-4 connections from the client and emits a 'connection' event for each. The client doesn't ever close any of the incorrectly started connections.

Thanks. I really do think this bug should be a priority. Many commercial companies that don't know better try to hire people to develop against the socket.io framework, thinking it works well. Granted, socket.io is free, so maybe this commercial companies should start looking at commercial products. But again, I think this really needs to be prioritized as very high priority. This bug has existed since 0.7.0 and is easily reproducible.

@davidfooks, @theyak. I fixed this issue for me long time ago, and it works without a fuss.

To fix, you should:

  1. Apply this patch: https://github.com/LearnBoost/socket.io-client/pull/342
  2. Disable AJAX-handshake(and let handshake to be only via JSONP), as discribed in pull-request comment.

How do you disable AJAX handshake? I assume you can still use all the connection types, this will only affect handshake?

+1 please fix this :)

I had the same multiple connect on re-connect issue. I think this is a severe issue...
The cause is that the Socket.connect method is called but the conneting flag is only set to true after handshake is completed, in case one of the matbeReconnect timers (timers handling the reconnect) wake up during the handshake process, they will calll Socket.connect again causing multiple reconnects.
I have solved the issue by calling self.reconnecting at the beginning of Socket.connect method.

Any chance of merging this?
This bug is making a bad bug in my app as well.

This bug still exists. Tried both patches. No success.

+1 I have this problem a lot using xhr-polling I didn't try the patches yet

+1, I too have this problem with the duplicate reconnections.

Whenever Node.js is restarted (i.e. when running via supervisor), my client(s) reconnect X times the number of times Node.js has been restarted from the point where the client(s) connected initially. The bug causes events to be emitted once per reconnection from the client-side - this is not just a question of duplicates.

I tried socket.on('disconnect', function() { socket.disconnect(); }); on the client-side, but that does not work. :/

Investigating this a bit further, it seems I found what caused my problems. It's not a bug, but a wrong implementation of the client-side code from my part. facepalm This is what I originally had:

PROBLEM:

var socket = io.connect();

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

  console.log('User connected!');

  socket.on('message', function(message) {

    console.log(message);

  });

});

The above client-side JavaScript caused the multiple calls to console.log() when the client(s) reconnected. This is what I replaced the above with:

SOLUTION:

var socket = io.connect();

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

  console.log('User connected!');

});

socket.on('message', function(message) {

  console.log(message);

});

Now, multiple messages are not being sent back and forth when clients reconnect to the server. Can anybody else confirm that a change of their client-side code fixes the problem?

Hi. I had the same issue. When I was restarting node ( or when the connection timed-out ) and the client reconnected , I was receiving the same message emited by the server by n time ( where n was the number of reconnects ).
I solved this by moving all my handlers from inside the socket.on('connect' function() {... }); function to outside of it.

The code above does what it takes.
This is my full answer from the mailing list:
https://groups.google.com/forum/?hl=en&fromgroups#!topic/socket_io/X9FRMjCkPco

@xdanx, awesome, thanks for the reply.

yes, this seems to work for me too: putting the socket.on('message') code separate from 'connect' event code

But what about "Connection"?
And what about the "socket" object in callback?

/edit Nevermind, I see, 'connect' is on the client. I was still getting issue with reconnect spamming when I hadn't done that. But that was in 0.9.6

I seem to have the same problem as well... Tried the above fix of moving the message code to seperate blocks.. but noticed that I never had it together.

any news on other workarrounds for this in 0.9.8?

I have the same problem. I have 0.9.10 installed. Any way to fix this? :(
btw its been 1+ year and no fix yet .. :(

EDIT.

The problem seems to be gone when I'm only using jsonp-polling.
io.set('transports', [ 'jsonp-polling' ]);

I have the same problem.
socket.[email protected]
node v0.8.8

@semprom I think using jsonp-polling fixes it because it might be relavant to websocket connections only.

Unfortunately for me my entire implementation kind of relies on the feedback being as quick as possible, so websockets as opposed to polling works best,, And since I am in control of the clients connecting I see no reason except for this issue to move to anything else.

Note that the multiple connections from the same client reconnecting have the same socket.id. So you can maintain your own list of socket ids and ignore duplicates to workaround this issue.

@KasperTidemann Thanks. It solved this problem.

@esanai No problem, glad it worked!

Hi, I have the same problem and I noticed that every time the connection is reconnected, a new client socket id is created. The solution is either use io.set('transports', [ 'jsonp-polling' ]); or use KasperTidemann's solution?

@KasperTidemann My goodness, man, that is exactly the answer to my problems! See this commit: https://github.com/samuelclay/NewsBlur/commit/76cbbd8d8b2a787985bba724dc3562108492b017#L2L3887

I can reproduce a double connection event following a connection error at will with this simple client and server code in a single node.js file:

"use strict";

var server = require('socket.io');
var client = require('socket.io-client');

setTimeout(function () {
    var io = server.listen(8888);

    io.of('/chat').on('connection', function (socket) {
        console.log('Server: /chat connection');
        socket.emit('greeting', 'Hello, who are you?');
    });

    io.sockets.on('connection', function (socket) {
        console.log('Server: connection');
    });
}, 2000);

var socketAddress = 'http://localhost:8888/chat';
var socket = client.connect(socketAddress);

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

socket.on('greeting', function (data) {
    console.log("Client: greeting: ", data);
});

socket.on('error', function () {
    console.log("Client: error");
    socket.socket.reconnect();
});

Any work a rounds or fixes in sight?

Sorry I also posted this to issue #474.

I can reproduce this error fairly consistently using an iPhone with iOS 9.3.2 and Chrome Version 50.0.2661.95 and on Safari for iOS with version 1.4.6 of Socket.IO

I am only able to reproduce this on mobile and it hangs my page on the request to socket.io.

I have a simple .on('connect', function(socket) { console.log('Connected'); }); and it logs Connected twice when the error occurs which leads me to believe it is trying to open multiple socket connections at the same time.

screenshot 2016-05-27 13 03 44

Does anyone know a workaround for this?

Why was this issue closed ??

My example code of Apr 14, 2014 above no longer produce double connection events. There is a connect event for '/chat' and one for the socket itself. Which seems reasonable.

There is also no error even in the client anymore.

This is with socket.io 1.4.8 and node 6.3.0.

This bug is affecting me atm.

Apparently, when the socket_handlers are placeD withing routes, they are called multiple times. Use the socket connection within app.js and require handlers within the socket connection, pass the socket as a parameter. Note that some properties may not be shipped together with the socket instance

@leemlwando please open a new issue if needed.

I had the same problem what i did was to make a manual reconnect function on the client and call io.destroy(); inside the reconnect function this fixed the issue.

Thanks a lot @leemlwando Your last comment made my solve my stuff.

I am still getting this bug , is there any update ?

I think the only real bug here is that the internet is full of bad example code where socket.on() calls are wrapped inside the socket.on('connect') handler. Each time the socket reconnects, new instances of the handlers are stacked on top of the existing ones and this results in multiple calls upon each event. Don't do this: see @KasperTidemann's reply from 25 Jul 2012.

Perhaps DrLexO, except the code I presented above demonstrated the problem. It has no socket.on() wrapped inside any socket.on('connect') handler.

After all these years I surprised to still be notified about this bug. I have no idea if it's a thing still or not. Do I have to try it again?

@KasperTidemann thanks, it actually resolved the issue.

How can you define your event listeners _outside_ of the connect listener when you don't have access to the socket?

const app = express();
const http = require('http').createServer(app);
const io = require('socket.io')(http);

io.on('connect', function(socket) {

  // only now that we are inside the connect callback do we have access to the socket

  socket.on('join', function(room, user) {
  });

  socket.on('add_message', function(room, user) {
  });

  socket.on('disconnect', function(room, user) {
  });
});

People seem to be suggesting that event listeners (join, add_message and disconnect) should live independently, _outside_ the connect listener, but how is that possible without socket being defined?

io.on('connect', function(socket) {
  // socket is only available here
});

// socket is undefined here

socket.on('join', function(room, user) {
});

socket.on('add_message', function(room, user) {
});

socket.on('disconnect', function(room, user) {
});

Is there a different way to instantiate socket so that this is possible?

Why is this closed? @michael-lynch has a valid point

I would also like to know the answer to @michael-lynch's point.

@DrLex0 on the socket.io website example it even shows to do the following:

io.on('connection', function(socket){
  socket.on('chat message', function(msg){
    io.emit('chat message', msg);
  });
});
Was this page helpful?
0 / 5 - 0 ratings

Related issues

windwalker picture windwalker  ·  7Comments

MickL picture MickL  ·  12Comments

Gorokhov picture Gorokhov  ·  42Comments

twistedpixel picture twistedpixel  ·  26Comments

denisu picture denisu  ·  53Comments