Socket.io: Múltiplos soquetes abertos após reconectar

Criado em 28 jul. 2011  ·  54Comentários  ·  Fonte: socketio/socket.io

Percebi isso tanto no meu aplicativo socket.io quanto no de outra pessoa. Quando ocorre uma reconexão, é comum que mais de um soquete em um cliente seja aberto, o que nunca deveria acontecer.

Aqui está um log que obtive de meu próprio aplicativo de teste quando tive uma desconexão / reconexão.

** Desconectar* * Reconectando com atraso 1000 tentativas: 1
** Reconectando com atraso 2.000 tentativas: 2* * Conectando com xhr-polling
** Conexão com xhr-polling* * Reconecte com tipo de transporte xhr-polling Tentativas: 2
** Conectado* * Conectado

Quando isso acontece, recebo mensagens duplicadas, uma para cada soquete conectado, embora deva haver apenas um. É confirmado pelo Firebug que existem, de fato, dois sockets do cliente conectados. Meu melhor palpite é que isso está no código do cliente, talvez não fechando a primeira tentativa de reconexão.

Claro, a verdadeira questão pode ser por que houve uma desconexão em primeiro lugar?

Socket.IO client bug

Comentários muito úteis

Investigando um pouco mais adiante, parece que descobri o que causou meus problemas. Não é um bug , mas uma implementação errada do código do lado do cliente da minha parte. facepalm Isto é o que eu originalmente tinha:

PROBLEMA:

var socket = io.connect();

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

  console.log('User connected!');

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

    console.log(message);

  });

});

O JavaScript do lado do cliente acima causou várias chamadas para console.log () quando o (s) cliente (s) se reconectaram. Substituí o anterior por:

SOLUÇÃO:

var socket = io.connect();

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

  console.log('User connected!');

});

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

  console.log(message);

});

Agora, várias mensagens não estão sendo enviadas e voltadas quando os clientes se reconectam ao servidor. Alguém mais pode confirmar se uma alteração no código do lado do cliente corrige o problema?

Todos 54 comentários

A desconexão é disparada porque, tecnicamente, o cliente se desconectou do servidor. E é desconectado até que o evento de reconexão seja disparado novamente.

Mas o resto é um bug.

Acho que este é o motivo de um bug em meu aplicativo também -

No lado do servidor, criei um cursor disponível no mongodb para disparar sempre que houver uma nova inserção. Esta mensagem é então enviada via io.sockets.emit () para todos os conectados.

Mas, em vez de receber apenas uma mensagem por evento, recebo várias mensagens repetidas do lado do cliente.

Estou em uma conexão de internet extremamente não confiável, então meu palpite é que esse bug está afetando meu código também.

Vocês estavam usando Expressjs? Eu tive esse problema com o Express, reescrevi sem e funcionou bem.

Express não teria absolutamente nada a ver com este @mfkp , deve ter feito algo estranho

De acordo com @visionmedia , é um bug no socket.io não no Express. Como a implementação de reconexão atual ainda foi projetada para 0,6, está faltando algumas verificações e limpezas.

Ah, entendo. Esqueça, continue ;-)

+1 para isso. Problema intermitente em nosso aplicativo de bate-papo, onde socket.io abre várias conexões. O cliente então recebe duplicatas de todas as emissões.

+1. Websockets e cromo. O laptop entra em hibernação -> o aplicativo se reconecta após o despertar -> eventos duplos. Acontece apenas ao conectar ao servidor remoto. Não é possível reproduzir isso localmente, deve haver algum problema de latência de reconexão / rede.

Existe alguma solução alternativa para eliminar a conexão múltipla depois disso ?, por exemplo, do lado do cliente, se eu fizer socket.disconnect (), ele desconectará todas as conexões? Como quero evitar várias atualizações. segue funciona?
socket = io.connect (url)
socket.on ('conectar', função () {
if (multipleConnect) {
socket.disconnect ();
socket.removeAllListeners ('conectar');
io.sockets = {};
socket = io.connect (url);
socket.on ('conectar', functionToConnect);
}
})

Por favor, leia este https://github.com/LearnBoost/socket.io/issues/474#issuecomment -2833227.
Isso explica por que esse bug ocorre e como pode ser reproduzido.

@ 3rd-Eden - Alguma ideia de onde essa correção se encaixa na sua lista de tarefas / prioridades? Tenho um aplicativo que estou criando e planejando usá-lo para ele e adoraria poder dizer ao meu cliente que ele se reconectará corretamente a partir de dispositivos iOS. Ele se desconecta depois que o aplicativo é colocado em segundo plano ou o dispositivo é colocado em hibernação.

Ou você tem alguma ideia sobre como posso codificar uma solução alternativa? Estive trabalhando em algumas coisas nos últimos dias, mas o melhor dos casos sempre parece deixar muitas conexões abertas e descartar todos os dados armazenados nos soquetes. Os dados não são o fim do mundo. Posso usar o gatilho de reconexão do cliente para resolver esse problema, mas as conexões simultâneas são um pouco feias.

Obrigado!

@cris Não tenho certeza se este é o mesmo bug que você mencionou. Eu tenho um exemplo muito simples do bug sem lentidão no servidor.

Posso reproduzir claramente esse problema:

  1. Implemente um cliente de pulsação simples que envia pulsações em intervalos de 1 segundo.
  2. Conte o número de novas conexões do lado do servidor.
  3. Conte o número de desconexões do lado do servidor.
  4. Inicie o servidor e faça uma conexão com um cliente.
  5. Interrompa a conexão de rede entre o cliente e o servidor.
  6. Aguarde até que o servidor expire e emita um evento de desconexão.
  7. Reconecte a conexão de rede.

Observe que quando o cliente se reconecta, ele cria de 2 a 4 conexões, emitindo um evento de 'conexão' para cada uma. O servidor recebe de 2 a 4 conexões do cliente e emite um evento de 'conexão' para cada uma. O cliente nunca fecha nenhuma das conexões iniciadas incorretamente.

Obrigado. Eu realmente acho que esse bug deve ser uma prioridade. Muitas empresas comerciais que não sabem melhor tentam contratar pessoas para desenvolver contra a estrutura socket.io, pensando que funciona bem. Concedido, socket.io é gratuito, então talvez essas empresas comerciais devam começar a olhar para produtos comerciais. Mas, novamente, acho que isso realmente precisa ser priorizado como prioridade muito alta. Este bug existe desde a 0.7.0 e é facilmente reproduzível.

@davidfooks , @theyak. Eu resolvi esse problema para mim há muito tempo e ele funciona sem problemas.

Para corrigir, você deve:

  1. Aplique este patch: https://github.com/LearnBoost/socket.io-client/pull/342
  2. Desative o handshake de AJAX (e deixe o handshake ser apenas via JSONP), conforme descrito no comentário de solicitação de pull.

Como você desativa o handshake AJAX? Presumo que você ainda possa usar todos os tipos de conexão, isso afetará apenas o handshake?

+1, corrija isso :)

Eu tive o mesmo problema de conexão múltipla ao reconectar. Eu acho que este é um problema grave ...
A causa é que o método Socket.connect é chamado, mas o sinalizador de conexão só é definido como verdadeiro após a conclusão do handshake, caso um dos temporizadores matbeReconnect (temporizadores que manipulam a reconexão) acorde durante o processo de handshake, eles chamarão de Socket. conecte novamente causando múltiplas reconexões.
Resolvi o problema chamando self.reconnecting no início do método Socket.connect.

Alguma chance de mesclar isso?
Esse bug também está causando problemas no meu aplicativo.

Este bug ainda existe. Tentei os dois patches. Sem sucesso.

+1 Eu tenho muito esse problema com o xhr-polling Eu não tentei os patches ainda

+1, eu também tenho esse problema com as reconexões duplicadas.

Sempre que o Node.js é reiniciado (ou seja, ao ser executado via supervisor), meus clientes se reconectam X vezes o número de vezes que o Node.js foi reiniciado a partir do ponto em que o (s) cliente (s) se conectaram inicialmente. O bug faz com que os eventos sejam emitidos uma vez por reconexão do lado do cliente - isso não é apenas uma questão de duplicatas.

Tentei socket.on('disconnect', function() { socket.disconnect(); }); no lado do cliente, mas não funcionou. : /

Investigando um pouco mais adiante, parece que descobri o que causou meus problemas. Não é um bug , mas uma implementação errada do código do lado do cliente da minha parte. facepalm Isto é o que eu originalmente tinha:

PROBLEMA:

var socket = io.connect();

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

  console.log('User connected!');

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

    console.log(message);

  });

});

O JavaScript do lado do cliente acima causou várias chamadas para console.log () quando o (s) cliente (s) se reconectaram. Substituí o anterior por:

SOLUÇÃO:

var socket = io.connect();

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

  console.log('User connected!');

});

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

  console.log(message);

});

Agora, várias mensagens não estão sendo enviadas e voltadas quando os clientes se reconectam ao servidor. Alguém mais pode confirmar se uma alteração no código do lado do cliente corrige o problema?

Oi. Eu tive o mesmo problema. Quando eu estava reiniciando o nó (ou quando a conexão expirou) e o cliente reconectou, eu estava recebendo a mesma mensagem emitida pelo servidor por n tempo (onde n era o número de reconexões).
Resolvi isso movendo todos os meus manipuladores de dentro do socket.on ('connect' function () {...}); função para fora dela.

O código acima faz o que for preciso.
Esta é minha resposta completa da lista de e-mails:
https://groups.google.com/forum/?hl=en&fromgroups#!topic/socket_io/X9FRMjCkPco

@xdanx , incrível, obrigado pela resposta.

sim, isso parece funcionar para mim também: colocar o código socket.on ('mensagem') separado do código de evento 'conectar'

Mas e quanto a "Conexão"?
E quanto ao objeto "socket" no retorno de chamada?

/ edit Deixa pra lá, eu vejo, 'conectar' está no cliente. Eu ainda estava tendo problemas com spam de reconexão quando não tinha feito isso. Mas isso foi em 0.9.6

Parece que tenho o mesmo problema também ... Tentei a correção acima de mover o código da mensagem para blocos separados ... mas notei que nunca o tive junto.

alguma notícia sobre outras soluções alternativas para isso em 0.9.8?

Eu tenho o mesmo problema. Tenho 0.9.10 instalado. Algum jeito de arrumar isso? :(
btw, já faz mais de 1 ano e nenhuma correção ainda .. :(

EDITAR.

O problema parece ter desaparecido quando estou usando apenas o jsonp-polling.
io.set ('transportes', ['jsonp-polling']);

Eu tenho o mesmo problema.
socket. [email protected]
nó v0.8.8

@semprom Acho que usar o jsonp-polling corrige isso porque pode ser relevante apenas para conexões de websocket.

Infelizmente, para mim, toda a minha implementação depende de que o feedback seja o mais rápido possível, então websockets em vez de polling funcionam melhor, E como estou no controle da conexão dos clientes, não vejo razão, exceto para esse problema, para mudar para qualquer coisa outro.

Observe que as várias conexões do mesmo cliente reconectando têm o mesmo socket.id . Portanto, você pode manter sua própria lista de ids de soquete e ignorar duplicatas para solucionar esse problema.

Obrigado @KasperTidemann . Isso resolveu esse problema.

@esanai Sem problemas, que bom que funcionou!

Olá, estou com o mesmo problema e notei que toda vez que a conexão é reconectada, um novo ID de socket de cliente é criado. A solução é usar io.set ('transports', ['jsonp-polling']); ou usar a solução KasperTidemann?

@KasperTidemann Meu Deus, cara, essa é exatamente a resposta para os meus problemas! Veja este commit: https://github.com/samuelclay/NewsBlur/commit/76cb thirtyd8b2a787985bba724dc3562108492b017#

Posso reproduzir um evento de conexão dupla após um erro de conexão à vontade com este código de cliente e servidor simples em um único arquivo 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');
        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();
});

Algum trabalho em rodadas ou consertos à vista?

Desculpe, também postei isso na edição # 474.

Posso reproduzir esse erro de forma bastante consistente usando um iPhone com iOS 9.3.2 e Chrome versão 50.0.2661.95 e no Safari para iOS com versão 1.4.6 de Socket.IO

Só consigo reproduzir isso no celular e trava minha página na solicitação ao socket.io.

Eu tenho um simples .on ('conectar', função (soquete) {console.log ('Conectado');}); e ele registra Conectado duas vezes quando ocorre o erro, o que me leva a acreditar que ele está tentando abrir várias conexões de soquete ao mesmo tempo.

screenshot 2016-05-27 13 03 44

Alguém conhece uma solução alternativa para isso?

Por que este problema foi encerrado ??

Meu código de exemplo de 14 de abril de 2014 acima não produz mais eventos de conexão dupla. Há um evento de conexão para '/ chat' e outro para o próprio soquete. O que parece razoável.

Também não há mais erro nem no cliente.

Isso ocorre com socket.io 1.4.8 e node 6.3.0.

Este bug está me afetando atm.

Aparentemente, quando os socket_handlers são colocados em rotas, eles são chamados várias vezes. Use a conexão de soquete em app.js e exija manipuladores dentro da conexão de soquete, passe o soquete como um parâmetro. Observe que algumas propriedades podem não ser enviadas junto com a instância de soquete

@leemlwando abra um novo problema se necessário.

Eu tive o mesmo problema que fiz foi fazer uma função de reconexão manual no cliente e chamar io.destroy (); dentro da função de reconexão, isso corrigiu o problema.

Muito obrigado @leemlwando Seu último comentário me fez resolver minhas coisas.

Ainda estou recebendo esse bug, há alguma atualização?

Acho que o único bug real aqui é que a Internet está cheia de códigos de exemplo ruins onde as chamadas socket.on () são agrupadas dentro do manipulador socket.on ('conectar'). Cada vez que o soquete é reconectado, novas instâncias dos manipuladores são empilhadas sobre as existentes e isso resulta em várias chamadas em cada evento. Não faça isso: veja a resposta de @KasperTidemann de 25 de julho de 2012.

Talvez DrLexO, exceto o código que apresentei acima demonstrou o problema. Não tem socket.on () dentro de nenhum manipulador socket.on ('connect').

Depois de todos esses anos, fiquei surpreso por ainda ser avisado sobre esse bug. Não tenho ideia se é uma coisa parada ou não. Tenho que tentar de novo?

@KasperTidemann obrigado, realmente resolveu o problema.

Como você pode definir seus ouvintes de eventos _fora_ do connect listener quando você não tem acesso ao 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) {
  });
});

As pessoas parecem estar sugerindo que os ouvintes de eventos ( join , add_message e disconnect ) devem viver independentemente, _fora_do_ ouvinte connect , mas como isso é possível sem socket sendo definido?

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

Existe uma maneira diferente de instanciar socket para que isso seja possível?

Por que isso está fechado? @ michael-lynch tem um ponto válido

Eu também gostaria de saber a resposta ao ponto de @michael-lynch.

@ DrLex0 no exemplo do site socket.io mostra até mesmo fazer o seguinte:

io.on('connection', function(socket){
  socket.on('chat message', function(msg){
    io.emit('chat message', msg);
  });
});
Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

Aweather picture Aweather  ·  4Comentários

doughsay picture doughsay  ·  4Comentários

gCurtisCT picture gCurtisCT  ·  4Comentários

thebinarypenguin picture thebinarypenguin  ·  4Comentários

dmuth picture dmuth  ·  3Comentários