Socket.io: Conexión doble

Creado en 23 ago. 2011  ·  42Comentarios  ·  Fuente: socketio/socket.io

de alguna manera ocurre una doble conexión con los clientes (lo que significa que todos los controladores son llamados dos veces), no pude reproducir la situación por mi cuenta, pero sigo recibiendo informes de errores, el comportamiento es exactamente el mismo si llama a socket.socket.connect () ya conectado socket. (probado en websocket y flashsocket)

Socket.IO client bug

Comentario más útil

Todavía me encuentro con este problema siguiendo el ejemplo básico.

EDITAR: Encontré una solución, aunque no estoy seguro de que sea exactamente adecuada. Básicamente, todo lo que requiere es usar

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

en vez de

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

Todos 42 comentarios

como truco rápido puede usar "forzar nueva conexión": configuración falsa

También observé este error en nuestra aplicación.
Reproduce fue el siguiente. En FF con conexión websocket, ocurrió algún error. Luego, uno tras otros 3 eventos de reconexión se habían generado. Después de esto, se establecieron 3 nuevas conexiones y el navegador recibió 3 mensajes en lugar de uno.

¿Quizás algún error en la lógica de reconexión? Algo, que genera varias reconexiones en lugar de una.

He visto problemas en navegadores más antiguos que no admiten websockets (por ejemplo, FF 3.6) donde la inicialización de socket.io en el evento dom ready ("$ ()" en jQuery) causa múltiples conexiones mientras se inicializa en la ventana posterior. el evento no lo hace. Descubrí que este problema en particular se puede reproducir de manera consistente. No estoy seguro de si es lo mismo que está viendo, pero los síntomas se ven muy similares.

El mismo problema aquí también. El problema es que si el servidor se bloquea por cualquier motivo y luego se vuelve a encender, la reconexión da como resultado n + 1 respuestas cada vez. así que si tenemos, digamos, 3 fallas del servidor, tendremos 4 respuestas en cada servidor emitido. Actualizar la página resuelve el problema. ¿Alguien ha encontrado una solución para esto [aunque sea temporal?]

Puede que esta no sea una solución permanente, pero reorganicé mi código para que cada evento se vincule de forma independiente y el problema de duplicación parece haberse resuelto en la reconexión automática

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

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

});

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

});

Después de una semana de depuración a través del volcado de Wireshark capturado, me las arreglé para encontrar el motivo y reproducir este error.

En resumen, la lógica de reconexión es muy frágil. Depende de muchos temporizadores que pueden funcionar en paralelo y conduce a varias reconexiones. Esta línea https://github.com/LearnBoost/socket.io-client/blob/master/lib/socket.js#L511 es la razón principal de este error.

Ahora reproducción completa:

  1. Conéctese con el cliente al servidor.
  2. Ponga código lento en su servidor (deberíamos suspender el mainloop de node.js durante 4-8 segundos) a través de factorial:
    función fibo (n) {
    si (n <2) devuelve 1;
    devuelve fibo (n-2) + fibo (n-1);
    }
    Ponlo en la sección de autenticación. Esto debería llamarse en apretón de manos:
    io.set ('autorización', función (datos, aceptar) {
    console.info ("Fibo ::" + fibo (41));
    Debería experimentar en su consola de nodo, para encontrar fibo (N), que
    bloqueará el bucle principal durante 4-8 segundos.
  3. Ahora, debe reiniciar rápidamente su servidor.
    Se aplicará un código lento para la conexión.
    Se debe notificar al cliente que no se apretó la mano
    Y ahora intenta volver a conectarse.
    En la consola, verá varios intentos de reconexión (si activa el inicio de sesión en las devoluciones de llamada "reconectar / reconectar").
    Después de nuestro truco de desaceleración, se repetirá para siempre.

En la vida real, esto se reproducía a través de la ralentización de la respuesta del servidor al menos durante varios segundos.
Esto puede ocurrir cuando node.js está bajo una carga pesada y responde con cierta demora.
O alguna ralentización de la red también puede conducir a tal comportamiento.
También se puede reproducir después de reiniciar el servidor.

Esta línea (socket.js, 511):
self.reconnectionTimer = setTimeout (tal vezReconnect, self.reconnectionDelay);

programa el evento después de la llamada de conexión. Y si la respuesta de conexión se retrasa al menos un segundo, se activa y se coloca una nueva reconexión en la cola. Después de 2 segundos agrega otro y así uno.

Hice una solución, pero no está probado y no parece muy sólido. Problema principal: cómo razonar sobre qué devolución de llamada / temporizador se puede ejecutar al mismo tiempo para la función MaybeReconnect.
Esta línea: https://github.com/LearnBoost/socket.io-client/blob/master/lib/socket.js#L490 también puede conducir a una conexión duplicada.

El cliente Socket.io puede ser mucho más simple de razonar, si se refactoriza para usar alguna máquina de estado. Actualmente, el estado se distribuye a través de diferentes banderas (conectado, conectando, reconectando, etc.). Y en muchas funciones vi guardias como "if (! Self.reconnecting)" y muchos otros.
La máquina de estados puede simplificar esta lógica para tener un conjunto de estados y eventos. Y los temporizadores solo se pueden usar para disparar eventos. Si este evento alcanza un estado incorrecto, state-machine puede simplemente ignorar este evento y no molestarse.

No he encontrado un buen STM para JS, pero este de Ruby se puede portar fácilmente a JS: https://github.com/geekq/workflow

Definitivamente +1 para reparar este problema. He estado trabajando para tratar de encontrar una solución para este problema sin modificar socket.io o socket.io-client directamente, pero desafortunadamente el único método que he encontrado de manera confiable es simplemente deshabilitar la reconexión. Lo que definitivamente no es una buena solución, especialmente con el mayor uso de dispositivos móviles, la reconexión es un requisito enorme.

¿Alguien tiene alguna idea de cómo cae esto en la lista de prioridades de los desarrolladores?

¡Ah! Parece que este problema se ha asignado a 3rd-Eden desde el problema: https://github.com/LearnBoost/socket.io/issues/430

Hice una corrección para un cliente y envié una solicitud de extracción. Funciona bien en 0.8.4 y puede funcionar bien en otras versiones. Pero requiere deshabilitar en las fuentes la capacidad de usar AJAX (o CORS) para el protocolo de enlace. Vea esto: https://github.com/LearnBoost/socket.io-client/pull/342 para más detalles.

Perdón por revivir un problema tan antiguo. Creo que estoy usando la última versión de socket.io (o al menos, hice npm install socket.io). Este problema todavía me ocurre, soy relativamente nuevo en socket.io y node.js en su conjunto. También he tenido problemas en los que a veces la primera conexión (de las dos que solo he tenido en un momento determinado) tiene un error de lectura. Si estoy en lo cierto al decir cris, su solución se comprometió, por lo que ya no debería suceder, pero aún así, a menos que me haya perdido un factor importante.

Editar -

Parece que cris bifurcó socket.io e hizo una corrección en eso y la corrección no se comprometió con el socket.io original.

@JTallis Tuve el mismo problema que @gdiz y su sugerencia funcionó bien. Si tu problema es similar, te sugiero que lo pruebes y nos digas cómo funciona.

También tengo este problema con 0.9.16, que creo que es la versión más actual. ¿Cómo funciona gdiz para evitar que esto ocurra? No lo entendí completamente.

Dios mío ... paso varias horas para averiguar qué está mal con mi aplicación y por qué los mensajes entre el servidor y el cliente se duplicaron en masa después de que la conexión se perdió y se renovó ...

usando 0.9.16 puedo confirmar este problema

Puedo obtener un evento de doble conexión a voluntad con el siguiente código de cliente y servidor en el mismo archivo archivo 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();
});

Un par de cosas extrañas:

1) Si cambio la conexión de espacio de nombres a una normal eliminando "/ chat" de la URL, solo hay un evento de conexión.

2) Si inicio el servidor inmediatamente, cambio el tiempo de setInterval a cero, no hay error de conexión inicial y solo un evento de conexión.

¿Alguna solución o solución para esto?

Tener el mismo problema. Si el servidor socket.io se reinicia inesperadamente, el cliente se vuelve a conectar dos veces, por lo que cada mensaje es procesado dos veces por el cliente. Realmente arruina mis cuentas por parte del cliente.

Tengo el mismo problema con la versión 1.0.0-pre2. Tengo dos "400 solicitudes incorrectas" cuando reafirmo socket.io.

¡Examinaré esto hoy!

¡Examinaré esto hoy!

¡No lo dudes si necesitas más detalles, registros o pantallas! No todas las veces.

en el cliente socket.io.js en 1.0.6 en la línea 2755:

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

Creo que es una buena idea establecer:
xhr.timeout = instancia de Manager._timeout - 10 ms
De esta manera, evita la creación de múltiples sockets de cliente en el lado del cliente.
En el lado del servidor, varios sockets se agotarán.

El ejemplo básico de socket.io "Getting Started" (http://socket.io/get-started/chat/) tiene este problema de conexión de doble socket.

Uno de los siguientes (en orden creciente de probabilidad) da como resultado la conexión de doble socket desde una sola conexión de pestaña del navegador:
a) Al conectarse a localhost: 3000, desde la primera pestaña del navegador
b) Al conectarse a localhost: 3000, desde una segunda pestaña del navegador
c) Mantener abierta la consola del navegador antes de conectarse a (localhost: 3000)

Observaciones adicionales:

 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. Hay dos socket.id distintos que emanan de una sola solicitud de pestaña del navegador.
  2. La conexión de socket "duplicada" se desconecta, en aproximadamente un minuto con el archivo console.log de "undefined se ha desconectado del chat".
  3. Usando express generator 4.2 (usando Morgan) y luego implementando el ejemplo "Getting Started", las "buenas" conexiones del navegador dan como resultado registros rápidos de una sola línea, por ejemplo, "GET / 304 1ms". Pero siempre que exista esta conexión de socket "doble", hay dos registros rápidos, "GET / 304 1ms" Y "GET / 200 3ms - 386b"

Estoy usando Mac, Chrome, Express 4.2 y el último socket.io.

Existe una diferencia temporal entre la creación de los dos registros. El primer registro se activa cuando Chrome completa automáticamente mi "lo" a " localhost: 3000 " y el segundo registro se activa cuando presiono el botón Enter.

Tenía un mensaje de registro de la consola "X usuarios conectados" y era muy molesto cuando mi propio navegador activaba 2 o 3 avisos de conexión de usuario.

Ahora, debo confesar que mi solución al problema fue comentar la línea console.log. Pero sigan con el buen trabajo, muchachos.

Sigo viendo este problema en la última versión. ¿Alguna actualización sobre esto?

También veo este problema con 1.0

No puedo reproducirlo en absoluto. ¿Alguien puede publicar un ejemplo completo?

El viernes 14 de noviembre de 2014 a las 2:44:50 a. M. Rex Pechler [email protected]
escribió:

También veo este problema con 1.0

-
Responda a este correo electrónico directamente o véalo en GitHub
https://github.com/Automattic/socket.io/issues/474#issuecomment -62934229
.

Veré si puedo preparar un ejemplo simple mañana.

Podría reproducirlo. Estoy usando socket.io 1.3.5 y express 4.12.4.

Mi aplicación express se encuentra en 127.0.0.1:3000 y abro mi navegador y escribo esa dirección IP y socket.io abre solo un websocket.

Tengo un dominio como abc.com y lo reenvío a 127.0.0.1. Abro abc.com en mi navegador y en el archivo index.html está la línea;

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

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

esto abre 2 websockets.

Todavía no he probado nginx con proxy. Te lo haré saber tan pronto como lo intente.

screen shot 2015-05-29 at 23 53 29

Todavía encuentro este problema. Para mí, sucedió en el reinicio del servidor: estaba adjuntando mis controladores de eventos socket.on ('mensaje') cuando se disparó el evento de conexión inicial del servidor, y si el servidor se reiniciaba mientras el cliente estaba abierto, ese evento se activaba varias veces (más tiempo el más tiempo el cliente había estado esperando el reinicio del servidor).

Mi solución por ahora ha sido 'eliminar el rebote' del evento de socket adjunto para que solo ocurra en la primera conexión del servidor, así:

client.socketEventsAttached = false;

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

También puede colocar sus oyentes de eventos de mensajes fuera del oyente socket.on ('connect') como sugirió @gdiz . Acabo de tener algunos problemas con los eventos de socket que se activan antes de que el servidor o el cliente estén listos para ellos.

@bbcollinsworth ¿cuál es el objeto del cliente?

Todavía encuentro este problema con socketio nuevo y un ejemplo básico.

Todavía me encuentro con este problema siguiendo el ejemplo básico.

EDITAR: Encontré una solución, aunque no estoy seguro de que sea exactamente adecuada. Básicamente, todo lo que requiere es usar

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

en vez de

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

@brandonraphael, ¿ podría proporcionar un ejemplo que reproduzca su problema (basado en https://github.com/darrachequesne/socket.io-fiddle, por ejemplo) y abrir un nuevo problema?

Cualquier actualización, esto todavía está sucediendo y creando problemas en la aplicación

Estos son los registros:
0 | Servidor Api | ¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡Conectado!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! DKap3hUYFSpKBRr7AFgc 4351 2018-12-26 10:58:25
0 | Servidor Api | ¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡Conectado!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! VS98DBFVTNF6ifzmAFgd 4351 2018-12-26 10:58:25

4351 es la identificación del usuario y el número de conexiones tampoco es estático como 2 en el caso del usuario 4351.
Otro registro muestra 6 conexiones al mismo tiempo para el mismo usuario.

Además, he comprobado estos dos ID de socket en el servidor y se muestran válidos. Pero la interfaz solo puede escuchar uno de ellos, que siempre es el primer ID de socket.

Cualquier ayuda sería genial.
Gracias por adelantado.

Todavía me encuentro con este problema siguiendo el ejemplo básico.

EDITAR: Encontré una solución, aunque no estoy seguro de que sea exactamente adecuada. Básicamente, todo lo que requiere es usar

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

en vez de

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

gracias por esto

El problema se resolvió después de cambiar la versión utilizada en el cliente. Otra solución sería usar habitaciones en lugar de una única identificación de socket. Descubrí que cada ID de socket es en sí mismo una habitación, solo la parte que se iba a cambiar era el nuevo código de conexión de poner cada ID de socket en la habitación del usuario.
Considere que un usuario slug es User1, luego se creó una sala User1 y cada nueva conexión de socket a través de slug User1 se colocó dentro de la sala User1.

Estaba teniendo el mismo problema y me estaba volviendo loco. Definitivamente NO estaba volviendo a registrar los oyentes de eventos en el cliente tampoco. En mi configuración, tengo un servidor nodejs que aloja el punto final socketio y también tengo otro servidor nodejs que actúa como mi cliente socketio. El truco consistía en conectar el lado del cliente con el transporte websocket y usar forceNode . Ex

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

Creo que estoy teniendo el mismo problema. Estoy construyendo una sala de chat y cuando alguien se une a la sala, emito un "se ha unido a la sala "mensaje a la sala.

Todo funciona muy bien, pero si salgo de la habitación y luego entro por segunda vez, el mensaje de introducción se emite _dos veces_. Si salgo de la habitación de nuevo y vuelvo a entrar en ella por tercera vez, el mensaje de introducción se emite tres veces, y así sucesivamente. Cada _reconexión_ a la _misma_ sala da como resultado un mensaje de introducción duplicado. Sin embargo, si entro en una habitación _diferente_, solo veo el mensaje de introducción una vez.

Usar io.once('connection', ...) no funcionó para mí. De hecho, todos mis eventos dejaron de funcionar.

El uso del método "antirrebote" tampoco funcionó. Una vez más, ninguno de mis eventos se registró.

Por último, el uso del lado del cliente de la opción forceNode: true tampoco funcionó.

Estoy usando 2.2.0 tanto en el servidor como en el cliente. ¿Hay algo que me esté perdiendo?

Me preguntaba sobre el mismo problema, pero en última instancia, decirle al cliente que se conecte solo once ayudó.

Aquí está mi configuración para el cliente:

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

El cliente simplemente se registrará once para el evento connect , por lo que cualquier otro evento dentro de él se registraría una vez. Ahora, si el servidor falla, el cliente simplemente intentará volver a conectarse y no intentará crear una nueva conexión. Tan pronto como reciba la respuesta del servidor, comenzará a procesar los mensajes.

Por lo tanto, io.once debe configurarse en el lado del cliente, no en el lado del servidor.

Estoy usando la versión del cliente 2.1. Encuentro que es muy fácil activarlo en mi entorno de desarrollo. Cada vez que mi servidor de nodo se reinicia (por ejemplo, usando nodemon), el cliente siempre activa varios eventos de reconexión y luego se conecta incluso. Pero no puedo averiguar la causa raíz

Estoy usando la versión del cliente 2.1. Encuentro que es muy fácil activarlo en mi entorno de desarrollo. Cada vez que mi servidor de nodo se reinicia (por ejemplo, usando nodemon), el cliente siempre activa varios eventos de reconexión y luego se conecta incluso. Pero no puedo averiguar la causa raíz

Estaba teniendo el mismo problema que también con el propio nodemon. pero finalmente, decirle al cliente que se conectara solo once ayudó.
Prueba el código de mi respuesta justo arriba. Me ayudó y cada vez que se reinicia el servidor, los clientes obtienen nuevas conexiones.

Mi problema era simple

Tenía la misma aplicación del lado del cliente abierta en 2 pestañas. Ups

Yo también tuve el mismo problema. Sin embargo, para mí, puse por error mis controladores del lado del cliente dentro de la función de devolución socket.on('connection', cb) llamada

Aquí hay un fragmento para demostrar:

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

Cuando ocurriera una desconexión y reconexión, llamaría a socket.on('connect', cb) nuevamente, y el controlador myEvent registraría un segundo controlador con el mismo nombre. Entonces, cuando el servidor emitió myEvent nuevamente, tendría dos registros de consola del mismo mensaje.

Para resolverlo, tuve que poner mis otros controladores fuera del controlador 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}`);
});

Creo que mi confusión vino de cómo los documentos muestran que el lado del servidor coloca eventos socket.on dentro del evento connect . Eso depende de mí por no leer los documentos con más atención, pero pensé que pondría esto aquí en caso de que alguien más cometa el mismo error.

Además, aunque vi este problema en node.js específicamente, estoy seguro de que esto también sería un problema en el navegador.

¿Fue útil esta página
0 / 5 - 0 calificaciones