Socket.io: Double connexion

Créé le 23 août 2011  ·  42Commentaires  ·  Source: socketio/socket.io

d'une manière ou d'une autre, la double connexion arrive aux clients (ce qui signifie que tous les gestionnaires sont appelés deux fois), n'a pas pu reproduire la situation par moi-même, mais continuez à recevoir des rapports de bogue, le comportement est exactement le même si vous appelez socket.socket.connect () sur déjà connecté socket. (testé sur websocket et flashsocket)

Socket.IO client bug

Commentaire le plus utile

Je rencontre toujours ce problème en suivant l'exemple de base.

EDIT: J'ai trouvé un correctif, même si je ne suis pas sûr que ce soit exactement le bon. Il suffit essentiellement d’utiliser

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

au lieu de

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

Tous les 42 commentaires

comme hack rapide, vous pouvez utiliser "forcer une nouvelle connexion": fausse configuration

J'ai également observé ce bug dans notre application.
Reproduire était le suivant. Dans FF avec connexion websocket, une erreur s'est produite. Puis l'un après l'autre, 3 événements de reconnexion s'étaient produits. Une fois ces 3 nouvelles connexions établies, le navigateur a reçu 3 messages au lieu d'un.

Peut-être un bug dans la logique de reconnexion? Quelque chose, qui génère plusieurs reconnexions au lieu d'une.

J'ai vu des problèmes dans les navigateurs plus anciens qui ne prennent pas en charge les websockets (par exemple, FF 3.6) où l'initialisation de socket.io dans l'événement dom ready ("$ ()" dans jQuery) provoque plusieurs connexions lors de l'initialisation dans la fenêtre ultérieure. l'événement ne le fait pas. J'ai trouvé que ce problème particulier était toujours reproductible. Je ne sais pas si c'est la même chose que vous voyez, mais les symptômes sont très similaires.

Même problème ici aussi. Le problème est que si le serveur tombe en panne pour une raison quelconque, puis est remis sous tension, la reconnexion entraîne n + 1 réponses à chaque fois. donc si nous avons, disons 3 plantages de serveur, nous avons 4 réponses qui arrivent sur chaque émission de serveur. L'actualisation de la page résout le problème. Quelqu'un a-t-il trouvé une solution à ce problème [même si elle est temporaire?]

Ce n'est peut-être pas une solution permanente, mais j'ai réorganisé mon code afin que chaque événement soit lié indépendamment et que le problème de duplication semble avoir été résolu lors de la reconnexion automatique

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

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

});

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

});

Après une semaine de débogage via le dump Wireshark attrapé, j'ai réussi à trouver la raison et à reproduire ce bogue.

Bref, la logique de reconnexion est très fragile. Cela dépend de plusieurs minuteries qui peuvent fonctionner en parallèle et cela conduit à plusieurs reconnexions. Cette ligne https://github.com/LearnBoost/socket.io-client/blob/master/lib/socket.js#L511 est la principale raison de ce bogue.

Maintenant, reproduisez complètement:

  1. Connectez-vous avec le client au serveur.
  2. Mettez du code lent dans votre serveur (nous devrions suspendre la boucle principale de node.js pendant 4-8 secondes) via factorielle:
    fonction fibo (n) {
    si (n <2) renvoie 1;
    retourne fibo (n-2) + fibo (n-1);
    }
    Mettez-le dans auth-section. Cela devrait être appelé lors de la poignée de main:
    io.set ('autorisation', fonction (données, accepter) {
    console.info ("Fibo ::" + fibo (41));
    Vous devriez expérimenter dans votre console de nœuds, pour trouver fibo (N), qui
    bloquera la boucle principale pendant 4 à 8 secondes.
  3. Maintenant, vous devez redémarrer rapidement votre serveur.
    Un code lent s'appliquera pour la connexion.
    Le client doit être averti qu'il n'est pas établi de liaison.
    Et maintenant, il essaie de se reconnecter.
    Dans la console, vous verrez plusieurs tentatives de reconnexion (si vous mettez la connexion sur des rappels "reconnexion / reconnexion").
    Après notre hack de ralentissement, il sera répété pour toujours.

Dans la vraie vie, cela s'est reproduit via le ralentissement de la réponse du serveur au moins pendant plusieurs secondes.
Cela peut se produire lorsque node.js est soumis à une charge importante et répond avec un certain délai.
Ou un ralentissement du réseau peut également conduire à un tel comportement.
Il peut également être reproduit après le redémarrage du serveur.

Cette ligne (socket.js, 511):
self.reconnectionTimer = setTimeout (peut-êtreReconnect, self.reconnectionDelay);

programme l'événement après l'appel de connexion. Et si la réponse de connexion est retardée d'au moins une seconde, elle est déclenchée et met une nouvelle reconnexion dans la file d'attente. Après 2 secondes, il en ajoute un autre et ainsi un.

J'ai fait un correctif, mais il n'a pas été testé et n'a pas l'air très solide. Problème principal - comment raisonner sur quel rappel / minuterie peut être exécuté simultanément à la fonction peut-êtreReconnect.
Cette ligne: https://github.com/LearnBoost/socket.io-client/blob/master/lib/socket.js#L490 peut également conduire à une connexion dupliquée.

Le client Socket.io peut être beaucoup plus simple à raisonner s'il sera refactoré pour utiliser une machine d'état. Actuellement, l'état est réparti sur différents indicateurs (connecté, connexion, reconnexion, etc.). Et dans de nombreuses fonctions, j'ai vu des gardes comme "if (! Self.reconnecting)" et bien d'autres.
La machine d'état peut simplifier cette logique pour avoir un ensemble d'états et d'événements. Et les minuteries ne peuvent être utilisées que pour déclencher un événement. Si cet événement atteint un état incorrect, la machine d'état peut simplement ignorer cet événement et ne pas se déranger.

Je n'ai pas trouvé de bon STM pour JS, mais celui de Ruby peut être facilement porté sur JS: https://github.com/geekq/workflow

Certainement +1 en cas de réparation de ce problème. J'ai essayé de trouver une solution à ce problème sans modifier directement socket.io ou socket.io-client, mais malheureusement, la seule méthode que j'ai trouvée de manière fiable est simplement de désactiver la reconnexion. Ce qui n'est certainement pas une bonne solution, en particulier avec l'utilisation accrue des appareils mobiles, la reconnexion est une exigence énorme.

Quelqu'un a-t-il une idée de la façon dont cela s'inscrit dans la liste des priorités des développeurs?

Ah. Il semble que ce problème a été attribué à 3rd-Eden à partir du numéro: https://github.com/LearnBoost/socket.io/issues/430

J'ai fait un correctif pour un client et envoyé une demande d'extraction. Il fonctionne bien en 0.8.4 et peut bien fonctionner dans d'autres versions. Mais il faut désactiver dans les sources la capacité d'utiliser AJAX (ou CORS) pour la poignée de main. Voir ceci: https://github.com/LearnBoost/socket.io-client/pull/342 pour plus de détails.

Désolé d'avoir ravivé un si vieux problème. J'utilise Je crois que la dernière version de socket.io (ou du moins, j'ai installé socket.io par npm). Ce problème se produit toujours pour moi, je suis relativement nouveau dans socket.io et node.js dans leur ensemble. J'ai également eu des problèmes où parfois la première connexion (sur les deux que je n'ai eues qu'à un moment donné) a une erreur de lecture. Si j'ai raison de dire cris, votre correction a été validée, donc cela ne devrait plus se produire, mais cela se produit toujours à moins que j'ai raté un facteur important?

Éditer -

Il semble cris forké socket.io et fait un correctif à ce sujet et le correctif n'a pas été commis dans le socket.io d'origine?

@JTallis J'ai eu le même problème que @gdiz et sa suggestion a bien fonctionné. Si votre problème est similaire, je vous suggère de l'essayer et de nous dire comment cela fonctionne.

J'ai également ce problème avec la 0.9.16 qui, je crois, est la version la plus récente. Comment gdiz contournera-t-il ce problème? Je n'ai pas complètement compris.

omg ... je passe plusieurs heures à comprendre ce qui ne va pas avec mon application, et pourquoi les messages entre le serveur et le client sont dupliqués en masse après la perte de la connexion et le renouvellement ...

en utilisant la 0.9.16, je peux confirmer ce problème

Je peux obtenir un événement de double connexion à volonté avec le code client et serveur suivant dans le même fichier node.js:

"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();
});

Quelques choses étranges:

1) Si je change la connexion avec un espace de noms normal en supprimant le "/ chat" de l'url, il n'y a alors qu'un seul événement de connexion.

2) Si je démarre le serveur immédiatement, changez l'heure setInterval à zéro, il n'y a pas d'erreur de connexion initiale et un seul événement de connexion.

Des solutions ou des solutions pour cela?

Avoir le même problème. Si le serveur socket.io redémarre de manière inattendue, le client se reconnecte deux fois de sorte que chaque message est ensuite traité deux fois par le client. Vraiment gâche mes comptes sur le côté client.

J'ai le même problème avec la version 1.0.0-pre2. J'ai deux "400 Bad Request" quand je relance socket.io.

Regardons cela aujourd'hui!

Regardons cela aujourd'hui!

N'hésitez pas si vous avez besoin de plus de détails, de logs ou d'écrans! Ce n'est pas toujours le cas.

dans le client socket.io.js sur 1.0.6 à la ligne 2755:

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

Je pense que c'est une bonne idée de définir:
xhr.timeout = instance de Manager._timeout - 10 ms
De cette façon, vous empêchez la création de plusieurs sockets client côté client.
Du côté du serveur, plusieurs sockets auront un délai de pulsation.

L'exemple de base socket.io "Getting Started" (http://socket.io/get-started/chat/) présente ce problème de connexion à double socket.

L'un des éléments suivants (par ordre croissant de probabilité) entraîne la connexion à double socket à partir d'une seule connexion d'onglet de navigateur:
a) Lors de la connexion à localhost: 3000, à partir du premier onglet du navigateur lui-même
b) Lors de la connexion à localhost: 3000, à partir d'un deuxième onglet du navigateur
c) Garder la console du navigateur ouverte, avant de se connecter à (localhost: 3000)

Observations supplémentaires:

 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. Il y a deux socket.id distincts émanant d'une seule demande d'onglet de navigateur.
  2. La connexion socket "duplicate" se déconnecte d'elle-même, en environ une minute avec le console.log de "undefined s'est déconnecté du chat".
  3. En utilisant le générateur express 4.2 (en utilisant Morgan) puis en implémentant l'exemple "Getting Started", les "bonnes" connexions du navigateur aboutissent à des logs express d'une seule ligne, par exemple "GET / 304 1ms". Mais à chaque fois qu'il y a cette "double" connexion socket, il y a deux logs express, "GET / 304 1ms" ET "GET / 200 3ms - 386b"

J'utilise Mac, Chrome, Express 4.2 et le dernier socket.io.

Il existe un décalage temporel entre la création des deux journaux. Le premier journal est déclenché lorsque Chrome complète automatiquement mon "lo" en " localhost: 3000 " et le deuxième journal est déclenché lorsque j'appuie sur le bouton Entrée.

J'avais un message de journal de console "X utilisateurs connectés" et j'étais très ennuyeux quand mon propre navigateur a déclenché 2 ou 3 notifications de connexion utilisateur.

Maintenant, je dois avouer que ma solution au problème était de commenter la ligne console.log. Mais continuez votre bon travail, les gars.

Je vois toujours ce problème dans la dernière version. Des mises à jour à ce sujet?

Je vois également ce problème avec la version 1.0

Je ne peux pas le reproduire du tout. Quelqu'un peut-il publier un exemple complet?

Le ven 14 novembre 2014 à 02:44:50 Rex Pechler [email protected]
a écrit:

Je vois également ce problème avec la version 1.0

-
Répondez directement à cet e-mail ou affichez-le sur GitHub
https://github.com/Automattic/socket.io/issues/474#issuecomment -62934229
.

Je vais voir si je peux préparer un exemple simple demain.

Je pourrais le reproduire. J'utilise socket.io 1.3.5 et express 4.12.4.

Mon application express se trouve sur 127.0.0.1:3000 et j'ouvre mon navigateur et tape cette adresse IP et socket.io n'ouvre qu'un seul websocket.

J'ai un domaine tel que abc.com et je le transmets à 127.0.0.1. J'ouvre abc.com sur mon navigateur et dans le fichier index.html il y a la ligne;

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

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

cela ouvre 2 websockets.

Je n'ai pas encore essayé nginx avec proxy. Je vous informerai dès que j'essaierai.

screen shot 2015-05-29 at 23 53 29

Je rencontre toujours ce problème. Pour moi, cela s'est produit au redémarrage du serveur - je joignais mes gestionnaires d'événements socket.on ('message') lorsque l'événement de connexion initial du serveur a été déclenché, et si le serveur redémarrait alors que le client était ouvert, cet événement était déclenché plusieurs fois (plus le client attendait depuis longtemps le redémarrage du serveur).

Mon correctif pour le moment a été de `` rebondir '' l'événement de socket qui se connecte afin que cela ne se produise que lors de la première connexion au serveur, comme ceci:

client.socketEventsAttached = false;

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

Vous pouvez également placer vos écouteurs d'événements de message en dehors de l'écouteur socket.on ('connect') comme @gdiz l'a suggéré. J'ai juste eu quelques problèmes avec les événements de socket déclenchés avant que le serveur ou le client ne soit prêt pour eux.

@bbcollinsworth quel est l'objet client?

Je rencontre toujours ce problème avec un socketio frais et un exemple de base.

Je rencontre toujours ce problème en suivant l'exemple de base.

EDIT: J'ai trouvé un correctif, même si je ne suis pas sûr que ce soit exactement le bon. Il suffit essentiellement d’utiliser

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

au lieu de

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

@brandonraphael pourriez-vous s'il vous plaît fournir un exemple reproduisant votre problème (basé sur https://github.com/darrachequesne/socket.io-fiddle par exemple) et ouvrir un nouveau numéro?

Toute mise à jour qui se produit encore et crée des problèmes dans l'application

Ce sont les journaux -
0 | Serveur Api | Connecté!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! DKap3hUYFSpKBRr7AFgc 4351 2018-12-26 10:58:25
0 | Serveur Api | Connecté!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! VS98DBFVTNF6ifzmAFgd 4351 2018-12-26 10:58:25

4351 est l'identifiant de l'utilisateur et le nombre de connexions n'est pas non plus statique comme 2 dans le cas de l'utilisateur 4351.
Un autre journal montre 6 connexions en même temps pour le même utilisateur.

En outre, avez vérifié ces deux identifiants de socket sur le serveur et ils sont valides. Mais le frontend ne peut écouter que l'un d'entre eux qui est toujours le premier identifiant de socket.

Toute aide serait vraiment formidable.
Merci d'avance.

Je rencontre toujours ce problème en suivant l'exemple de base.

EDIT: J'ai trouvé un correctif, même si je ne suis pas sûr que ce soit exactement le bon. Il suffit essentiellement d’utiliser

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

au lieu de

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

Merci pour ça

Le problème a été résolu après la modification de la version utilisée du côté client. Une autre solution serait d'utiliser des salles au lieu d'un identifiant de socket unique. Nous avons découvert que chaque ID de socket est lui-même une pièce, seule une partie qui devait être modifiée était le nouveau code de connexion consistant à placer chaque ID de socket dans la salle utilisateur.
Considérons qu'un slug d'utilisateur est User1, puis une salle a été créée User1 et chaque nouvelle connexion de socket via le slug User1 a été placée dans la salle User1.

J'avais le même problème et cela me rendait fou. N'était certainement PAS réenregistrer les écouteurs d'événements sur le client non plus. Dans ma configuration, j'ai un serveur nodejs hébergeant le point de terminaison socketio et j'ai également un autre serveur nodejs agissant en tant que client socketio. L'astuce consistait à connecter le côté client avec le transport websocket et à utiliser forceNode . Ex

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

Je crois que j'ai ce même problème. Je construis une salle de chat et quand quelqu'un rejoint la salle, j'émets un "a rejoint la salle "message à la salle.

Tout fonctionne très bien, mais si je quitte la pièce et que j'y entre une seconde fois, le message d'introduction est émis _ deux fois_. Si je quitte à nouveau la pièce et y rentre une troisième fois, le message d'introduction est émis trois fois, et ainsi de suite. Chaque _reconnexion_ à la _ même_ salle entraîne un message d'introduction en double. Cependant, si j'entre dans une pièce _différente_, je ne vois le message d'introduction qu'une seule fois.

Utiliser io.once('connection', ...) n'a pas fonctionné pour moi. En fait, tous mes événements ont cessé de fonctionner.

L'utilisation de la méthode "anti-rebond" ne fonctionnait pas non plus. Encore une fois, aucun de mes événements ne s'est même enregistré.

Enfin, l'utilisation forceNode: true option

J'utilise 2.2.0 à la fois sur le serveur et le client. Y a-t-il quelque chose qui me manque?

Je me posais des questions sur le même problème, mais finalement, dire au client de se connecter uniquement once aidé.

Voici ma configuration pour le 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);
    });
}); 

Le client sera simplement enregistré once pour l'événement connect , donc tout autre événement à l'intérieur sera enregistré une fois. Maintenant, si le serveur tombe en panne, le client essaiera simplement de s'y reconnecter et n'essaiera pas de créer une nouvelle connexion. Dès qu'il reçoit la réponse du serveur, il commencera à traiter les messages.

Donc io.once doit être défini du côté client, pas du côté serveur.

J'utilise la version client 2.1. Je trouve qu'il est très facile de le déclencher dans mon environnement de développement. Chaque fois que mon serveur de nœuds redémarre (par exemple en utilisant nodemon), le client déclenche toujours plusieurs événements de reconnexion, puis se connecte même. Mais je ne peux pas comprendre la cause profonde

J'utilise la version client 2.1. Je trouve qu'il est très facile de le déclencher dans mon environnement de développement. Chaque fois que mon serveur de nœuds redémarre (par exemple en utilisant nodemon), le client déclenche toujours plusieurs événements de reconnexion, puis se connecte même. Mais je ne peux pas comprendre la cause profonde

J'avais le même problème que d'utiliser nodemon lui-même. mais finalement, dire au client de se connecter seulement once aidé.
Essayez le code de ma réponse juste au-dessus. Cela m'a aidé et à chaque redémarrage du serveur, les clients obtiennent de nouvelles connexions.

Mon problème était simple

J'ai eu la même application côté client ouverte sur 2 onglets. Oops

J'ai eu le même problème aussi. Cependant, pour moi, j'ai mis par erreur mes gestionnaires côté client dans la fonction de rappel socket.on('connection', cb) .

Voici un extrait de code pour démontrer:

client.js (dans 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}`);
  });
});

Lorsqu'une déconnexion et une reconnexion se produisaient, il appelait à nouveau socket.on('connect', cb) , et le gestionnaire myEvent enregistrerait un deuxième gestionnaire du même nom. Ainsi, lorsque le serveur émettrait à nouveau myEvent , j'aurais deux journaux de console du même message.

Pour résoudre, j'ai dû mettre mes autres gestionnaires en dehors du gestionnaire connect .

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

Je pense que ma confusion vient de la façon dont les documents montrent que le côté serveur met des événements socket.on à l'intérieur de l'événement connect . C'est à moi de ne pas avoir lu les documents plus attentivement, mais j'ai pensé que je mettrais ceci ici au cas où quelqu'un d'autre ferait la même erreur.

De plus, même si j'ai vu ce problème dans node.js spécifiquement, je suis sûr que ce serait également un problème dans le navigateur.

Cette page vous a été utile?
0 / 5 - 0 notes