Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Double connect #474

Closed
Gorokhov opened this issue Aug 23, 2011 · 42 comments
Closed

Double connect #474

Gorokhov opened this issue Aug 23, 2011 · 42 comments
Labels

Comments

@Gorokhov
Copy link

@Gorokhov Gorokhov commented Aug 23, 2011

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)

@dymsza
Copy link

@dymsza dymsza commented Sep 23, 2011

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

@cris
Copy link

@cris cris commented Oct 11, 2011

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.

@benblair
Copy link

@benblair benblair commented Nov 3, 2011

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.

@gdiz
Copy link

@gdiz gdiz commented Nov 10, 2011

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?]

@gdiz
Copy link

@gdiz gdiz commented Nov 10, 2011

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() {

});

@cris
Copy link

@cris cris commented Nov 22, 2011

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

@CameronJ
Copy link

@CameronJ CameronJ commented Nov 30, 2011

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?

@CameronJ
Copy link

@CameronJ CameronJ commented Nov 30, 2011

Ah. Looks like this issue has been assigned to 3rd-Eden from issue: #430

@cris
Copy link

@cris cris commented Dec 1, 2011

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: socketio/socket.io-client#342 for details.

@JTallis
Copy link

@JTallis JTallis commented Oct 26, 2013

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?

@misterdjules
Copy link

@misterdjules misterdjules commented Oct 28, 2013

@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.

@MrBunny956
Copy link

@MrBunny956 MrBunny956 commented Feb 22, 2014

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.

@EuPhobos
Copy link

@EuPhobos EuPhobos commented Mar 25, 2014

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...

@kindziora
Copy link

@kindziora kindziora commented Apr 10, 2014

using 0.9.16 i can confirm this issue

@ZiCog
Copy link

@ZiCog ZiCog commented Apr 14, 2014

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?

@KaptainKrayola
Copy link

@KaptainKrayola KaptainKrayola commented Apr 22, 2014

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.

@Maraumax
Copy link

@Maraumax Maraumax commented Apr 29, 2014

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

@rauchg
Copy link
Contributor

@rauchg rauchg commented Apr 29, 2014

Will look into this today!

@Maraumax
Copy link

@Maraumax Maraumax commented Apr 29, 2014

Will look into this today!

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

@ventzie
Copy link

@ventzie ventzie commented Jul 5, 2014

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.

@ubersensei
Copy link

@ubersensei ubersensei commented Jul 7, 2014

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.

@ffflabs
Copy link

@ffflabs ffflabs commented Jul 7, 2014

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.

@newelement
Copy link

@newelement newelement commented Oct 7, 2014

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

@rexfm
Copy link

@rexfm rexfm commented Nov 13, 2014

I'm seeing this issue with 1.0 as well

@rauchg
Copy link
Contributor

@rauchg rauchg commented Nov 14, 2014

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

On Fri Nov 14 2014 at 2:44:50 AM Rex Pechler notifications@github.com
wrote:

I'm seeing this issue with 1.0 as well


Reply to this email directly or view it on GitHub
#474 (comment)
.

@newelement
Copy link

@newelement newelement commented Nov 14, 2014

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

@leventmenekse
Copy link

@leventmenekse leventmenekse commented May 29, 2015

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

@bbcollinsworth
Copy link

@bbcollinsworth bbcollinsworth commented Mar 6, 2016

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.

@jyywhw
Copy link

@jyywhw jyywhw commented Feb 23, 2017

@bbcollinsworth what's the client object?

@Viskazz
Copy link

@Viskazz Viskazz commented Mar 9, 2017

Still encountering this issue with fresh socketio and basic example.

@brandonraphael
Copy link

@brandonraphael brandonraphael commented Mar 26, 2017

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', ...)

@darrachequesne
Copy link
Member

@darrachequesne darrachequesne commented Mar 27, 2017

@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?

@rd67
Copy link

@rd67 rd67 commented Dec 26, 2018

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.

@Gibigbig
Copy link

@Gibigbig Gibigbig commented Feb 21, 2019

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

@rd67
Copy link

@rd67 rd67 commented Feb 21, 2019

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.

@SimonVuong
Copy link

@SimonVuong SimonVuong commented Sep 25, 2019

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,
});

@michael-lynch
Copy link

@michael-lynch michael-lynch commented Sep 26, 2019

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?

@swr7der
Copy link

@swr7der swr7der commented Nov 14, 2019

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.

@qiulang
Copy link

@qiulang qiulang commented Nov 18, 2019

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

@swr7der
Copy link

@swr7der swr7der commented Nov 18, 2019

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.

@ohabash
Copy link

@ohabash ohabash commented Feb 10, 2020

My problem was simple

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

@joseph4tw
Copy link

@joseph4tw joseph4tw commented Oct 16, 2020

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.

This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet