Socket.io: Double connect

Created on 23 Aug 2011  ·  42Comments  ·  Source: socketio/socket.io

somehow double connect happens to clients(meaning all the handlers are called twice), could not reproduce the situation on my own, but keep receiving bug reports, the behavior is exactly the same if you call socket.socket.connect() on already connected socket.(tested on websocket and flashsocket)

Socket.IO client bug

Most helpful comment

I'm still encountering this issue as per following the basic example.

EDIT: I found a fix, although I'm not sure its exactly proper. Essentially all it requires is using

io.once('connection', ...)

instead of

io.on('connection', ...)

All 42 comments

as quick hack you can use "force new connection": false configuration

I also observed this bug in our application.
Reproduce was next. In FF with websocket connection, some error happened. Then one after other 3 reconnecting events had generated. After this 3 new connections was established, and browser received 3 messages instead of one.

Maybe some bug in reconnection logic? Something, which generates several reconnections instead of one.

I've seen issues in older browsers that don't support websockets (e.g., FF 3.6) where initializing socket.io in the dom ready event ("$()" in jQuery) causes multiple connections whereas initializing in the later window.load event does not. I've found this particular issue to be consistently reproducible. Not sure if it's the same thing you're seeing but the symptoms look very similar.

Same issue here as well. Problem is if the server crashes for whatever reason and then is powered back on, the reconnect results in n+1 responses every single time. so if we have say 3 server crashes, we have 4 responses coming in on each server emit. Refreshing the page resolves the issue. Has anyone found a solution for this [even if it is temporary?]

This may not be a permanent solution, but i rearranged my code so that each event is bound independently and the duplication issue seems to have been resolved on the auto reconnect

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

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

});

me.socket.on('disconnect', function() {

});

After a week of debugging via catched Wireshark dump, I've managed to find the reason and reproduce for this bug.

In short, reconnection logic is very fragile. It depends on many timers which can run in parallel and it leads to several reconnects. This line https://github.com/LearnBoost/socket.io-client/blob/master/lib/socket.js#L511 is a main reason for this bug.

Now full reproduce:

  1. Connect with client to server.
  2. Put slow code into your server (we should suspend node.js mainloop for 4-8 seconds) via factorial:
    function fibo(n) {
    if (n < 2) return 1;
    return fibo(n-2) + fibo(n-1);
    }
    Put it into auth-section. This should be called on handshake:
    io.set('authorization', function(data, accept) {
    console.info("Fibo :: " + fibo(41));
    You should experiment in your node console, to find fibo(N), which
    will block main-loop for 4-8 seconds.
  3. Now, you should do fast restart of your server.
    Slow code will apply for connection.
    Client should be notified it is not handshaked.
    And now it tries to reconnect.
    In console you will see several reconnect attemps(if you put logging on "reconnect/reconnecting" callbacks).
    After our slowdown hack it will be repeated forever.

In real life this reproduced via slowdown of server-reply at least for several seconds.
This can be when node.js is under heavy-load and responds with some delay.
Or some network slowdown can also lead to such behavior.
It can be also reproduced after server restart.

This line(socket.js, 511):
self.reconnectionTimer = setTimeout(maybeReconnect, self.reconnectionDelay);

schedules event after connect call. And if connect-response is delayed for at least one second, it is triggered and put new reconnect into queue. After 2 seconds it adds another one and so one.

I did a fix, but it isn't tested and looks not very solid. Main issue - how to reason about which callback/timer can be run concurrently to maybeReconnect function.
This line: https://github.com/LearnBoost/socket.io-client/blob/master/lib/socket.js#L490 can also lead to duplicated connection.

Socket.io client can be much more simple to reason about, if it will be refactored to use some State Machine. Currently state is spreaded across different flags(connected, connecting, reconnecting, etc). And in many functions I saw guards like "if (!self.reconnecting)" and many others.
State machine can simplify this logic to have set of states and events. And timers can be used only to fire event. If this event hit incorrect state, state-machine can just ignore this event and don't bother itself.

I haven't found good STM for JS, but this one from Ruby can be easily ported to JS: https://github.com/geekq/workflow

Definitely +1 on getting this issue repaired. I've been working on trying to find a work around for this problem without modifying socket.io or socket.io-client directly, but unfortunately the only method that I've reliably come up with is just disabling reconnect. Which is definitely not a good solution, especially with the increased usage of mobile devices, reconnecting is a huge requirement.

Does anyone have any idea how this falls on the developers priority list?

Ah. Looks like this issue has been assigned to 3rd-Eden from issue: https://github.com/LearnBoost/socket.io/issues/430

I've done a fix for a client and sent pull request. It works good in 0.8.4 and can work good in other versions. But it requires to disable in sources ability to use AJAX(or CORS) for handshake. See this: https://github.com/LearnBoost/socket.io-client/pull/342 for details.

Sorry for reviving such an old issue. I'm using I believe the latest version of socket.io (or at least, I did npm install socket.io). This issue still occurs for me, I'm relatively new to socket.io and node.js as a whole. I've also had issues where sometimes the first connection (out of the two that I've only had happen at any one time) has a read error. If I'm correct in saying cris, your fix was committed so it should not happen anymore but it still does unless I missed an important factor?

Edit -

It appears cris forked socket.io and made a fix on that and the fix was not committed to the original socket.io?

@JTallis I had the same issue as @gdiz and his suggestion worked well. If your issue is similar, I suggest you try it and let us know how it works.

I'm also having this issue with 0.9.16 which I believe is the most current version. How is gdiz work around preventing this from occurring? Didn't completely understand it.

omg... i spend several hours to figure out what's wrong with my app, and why messages between server and client mass duplicated after connection lost and renew...

using 0.9.16 i can confirm this issue

I can get a double connection event at will with the following client and server code in the same file 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');
    });

    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('error', function () {
    console.log("Client: error");
    socket.socket.reconnect();
});

A couple of odd things:

1) If I change the namespaced connection to a normal one by removing the "/chat" from the url there is then only one connection event.

2) If I start the server immediately, change the setInterval time to zero, there is no initial connection error and only one connection event.

Any work arounds or fixes for this?

Having the same issue. If the socket.io server restarts unexpectedly the client reconnects twice so every message is then processed twice by the client. Really messes up my counts on the client end.

I have same problem with 1.0.0-pre2 release. I have two "400 Bad Request" when i restard socket.io.

Will look into this today!

Will look into this today!

Do not hesitate if you need more details, logs or screens! It's not every times.

in client socket.io.js on 1.0.6 on line 2755:

Request.prototype.create = function(isBinary, supportsBinary){
var xhr = this.xhr = new XMLHttpRequest({ agent: this.agent, xdomain: this.xd });
...
}

I believe it is a good idea to set :
xhr.timeout = instance of Manager._timeout - 10 ms
This way you prevent multiple client socket creation on the client side.
On the server side multiple sockets will heartbeat timeout.

The basic socket.io "Getting Started" example (http://socket.io/get-started/chat/) has this double socket connection problem.

One of the following (in increasing order of probability) results in the double socket connection from a single browser tab connection:
a) Upon connecting to localhost:3000, from the first browser tab itself
b) Upon connecting to localhost:3000, from a second browser tab
c) Keeping the browser console open, before connecting to (localhost:3000)

Additional observations:

 io.on('connection', function(socket){
    console.log('a user connected: ' + socket.id);
    socket.on('disconnect', function(){
       console.log('a user disconnected');
       console.log(socket.nickname + ' has disconnected from the chat.');
    });
});
  1. There are two, distinct socket.id emanating from a single browser tab request.
  2. The "duplicate" socket connection disconnects itself, in roughly a minute with the console.log of "undefined has disconnected from the chat."
  3. Using express generator 4.2 (using Morgan) and then implementing the "Getting Started" example, the "good" browser connections result in express logs of a single line e.g. "GET / 304 1ms" . But whenever, there is this "double" socket connection, there are two express logs, "GET / 304 1ms" AND "GET / 200 3ms - 386b"

I'm using Mac, Chrome, Express 4.2 and the latest socket.io.

There is a timing difference between the creation of the two logs. The first log is fired when Chrome autocompletes my "lo" to "localhost:3000" and the second log is fired when I hit the enter button.

I had a "X users connected" console log message and was very annoying when my own browser triggered 2 or 3 user connection notices.

Now, I must confess my solution to the problem was commenting out the console.log line. But keep up the good work, guys.

I still see this issue in the latest version. Any updates on this?

I'm seeing this issue with 1.0 as well

Can't reproduce it at all. Can someone post a full example?

On Fri Nov 14 2014 at 2:44:50 AM Rex Pechler [email protected]
wrote:

I'm seeing this issue with 1.0 as well


Reply to this email directly or view it on GitHub
https://github.com/Automattic/socket.io/issues/474#issuecomment-62934229
.

I'll see if I can whip up a simple example tomorrow.

I might reproduce it. I am using socket.io 1.3.5 and express 4.12.4.

My express app sits on 127.0.0.1:3000 and i open up my browser and type that ip address and socket.io opens only one websocket.

I have a domain such as abc.com and i forward it to 127.0.0.1. I open abc.com on my browser and in index.html file there is the line;

<script>
        var socket = io('http://localhost:3000/mysql');

        socket.on('processlist', function (data){
            console.log(data);
        });
</script>

this opens 2 websockets.

I haven't tried nginx with proxy yet. I will let you know as soon as i try.

screen shot 2015-05-29 at 23 53 29

Still encountering this issue. For me it happened on server restart -- I was attaching my socket.on('message') event handlers when initial connection event from server fired, and if the server restarted while the client was open that event fired multiple times (more time the longer the client had been waiting for server restart).

My fix for now has been to 'debounce' the socket event attaching so it only happens on the first server connect, like so:

client.socketEventsAttached = false;

socket.on('connect',function(){
     if (!client.socketEventsAttached){
          attachSocketEvents();
     }
});

You can also put your message event listeners outside of the the socket.on('connect') listener as @gdiz suggested. I've just had some issues there with socket events firing before the server or client are ready for them.

@bbcollinsworth what's the client object?

Still encountering this issue with fresh socketio and basic example.

I'm still encountering this issue as per following the basic example.

EDIT: I found a fix, although I'm not sure its exactly proper. Essentially all it requires is using

io.once('connection', ...)

instead of

io.on('connection', ...)

@brandonraphael could you please provide an example reproducing your issue (based on https://github.com/darrachequesne/socket.io-fiddle for example) and open a new issue?

Any update this is still happening and creating problems in the app

These are the logs -
0|Api Server | Connected!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! DKap3hUYFSpKBRr7AFgc 4351 2018-12-26 10:58:25
0|Api Server | Connected!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! VS98DBFVTNF6ifzmAFgd 4351 2018-12-26 10:58:25

4351 is the user id and the number of connections is also not static like 2 in the case for user 4351.
Another log shows 6 connections at the same time for the same user.

Also, have checked these two socket ids on the server and they are showing valid. But the frontend is only able to listen to one of them which is always the first socket id.

Any help would be really great.
Thanks in advance.

I'm still encountering this issue as per following the basic example.

EDIT: I found a fix, although I'm not sure its exactly proper. Essentially all it requires is using

io.once('connection', ...)

instead of

io.on('connection', ...)

thank you for this

The issue got resolved after changing the version used on the client end. Another fix would be to use rooms instead of single socket id. Found out that every socket id is itself a room only part that was to be changed was of the new connection code of putting every socket id in user room.
Consider a user slug is User1 then a room was created User1 and every new socket connection via slug User1 was put inside the room User1.

Was having the same problem and it was driving me crazy. Was definitely NOT re-registering event listeners on client either. In my setup, I have a nodejs server hosting the socketio endpoint and I also have another nodejs server acting as my socketio client. The trick was to connect client side with websocket transport and use the forceNode. Ex

// client side
const socket = io('<url>', {
  transports: ['websocket'],
  forceNode: true,
});

I believe I'm having this same issue. I'm building a chat room and when someone joins the room, I emit a " has joined the room" message to the room.

Everything works great, but if I leave the room and then enter it a second time, the intro message is emitted _twice_. If I leave the room again and re-enter it a third time, the intro message is emitted three times, and so on. Every _reconnection_ to the _same_ room results in a duplicate intro message. However, if I enter a _different_ room, I only see the intro message once.

Using io.once('connection', ...) didn't work for me. In fact, all of my events stopped working.

Using the "debounce" method didn't work either. Again, none of my events even registered.

Lastly, using forceNode: true option client side didn't work either.

I am using 2.2.0 on both the server and client. Is there anything I'm missing?

I was wondering about the same issue, but ultimately, telling the client to connect only once helped.

Here's my config for the client:

var socket = io.connect("http://localhost:3000/test", 
    { upgrade: false, transports: ['websocket'], reconnection: true, forceNew: false});
socket.once('connect', socketConn => {
    socket.on('message', data => {
        console.log(data);
    });
}); 

The client will just be registered once for connect event, thus any other event inside it would be registered once. Now if the server will crash, the client will just try to reconnect to it and won't try to create a new connection. As soon as it gets the response from the server, it will start processing the messages.

So io.once need to be set on the client-side, not on the server side.

I am using client 2.1 version. I find it is very easy trigger it in my dev env. Every time my node server restarts (e.g. using nodemon) client always trigger several reconnect event then connect even. But I can't figure out the root cause

I am using client 2.1 version. I find it is very easy trigger it in my dev env. Every time my node server restarts (e.g. using nodemon) client always trigger several reconnect event then connect even. But I can't figure out the root cause

I was having the same issue that too using nodemon itself. but ultimately, telling the client to connect only once helped.
Try the code from my reply just above. It helped me and every time server restarts, clients are getting new connections.

My problem was simple

I had the same client-side app open on 2 tabs. oops

I had the same issue as well. However, for me, I mistakenly put my client-side handlers inside the socket.on('connection', cb) callback function.

Here's a snippet to demonstrate:

client.js (in node.js)

const client = require('socket.io-client');
const socket = client('my_endpoint', {
  transports: [ 'websockets' ]
});

socket.on('connect', () => {
  console.log('connected');
  socket.on('myEvent', (message) => {
    console.log(`message: ${message}`);
  });
});

When a disconnect and reconnect happened, it would call socket.on('connect', cb) again, and the myEvent handler would register a second handler of the same name. So when the server emitted myEvent again, I would have two console logs of the same message.

To resolve, I had to put my other handlers outside the connect handler.

const client = require('socket.io-client');
const socket = client('my_endpoint', {
  transports: [ 'websockets' ]
});

socket.on('connect', () => {
  console.log('connected');
});

socket.on('myEvent', (message) => {
  console.log(`message: ${message}`);
});

I think my confusion came from how the docs show the server-side putting socket.on events inside the connect event. That's on me for not reading the docs more carefully, but I figured I'd put this here in case someone else makes the same mistake.

Also, even though I saw this issue in node.js specifically, I'm sure this would be a problem in the browser as well.

Was this page helpful?
0 / 5 - 0 ratings