Socket.io: a desconexão do lado do cliente não é detectada

Criado em 11 nov. 2011  ·  58Comentários  ·  Fonte: socketio/socket.io

var socketio = io.connect(socketServer, 
                {rememberTransport: false, 
                'reconnect': true,
                'reconnection delay': 500,
                'max reconnection attempts': 10,
                'secure': true});

socketio.on('disconnect', function() {
    alert('client socketio disconnect!')
});

O alerta aparece se eu desativo o servidor Node, mas não se eu desligar minha rede sem fio ou fechar meu laptop e reabri-lo mais tarde. A conexão é perdida embora. Existe uma maneira melhor de detectar desconexão no lado do cliente? Isso é com o transporte WebSockets.

Comentários muito úteis

Por favor, reabra este ticket, pois ainda não foi corrigido!
Eu estava olhando para o arquivo: https://github.com/socketio/socket.io-client/blob/master/lib/manager.js para descobrir se existe alguma opção para isso, e encontrei timeout que é 20 segundos por padrão.
Mas quando tentei mudar para 4 segundos, simplesmente não funcionou.

Todos 58 comentários

Olá,

Você encontrou uma solução para isso?

Estou curioso sobre isso também. Estou tendo problemas para fazer com que os eventos de desconexão sejam acionados de forma confiável, independentemente da situação, mas isso pode ser minha culpa.

+1

Eu encontrei uma pseudo-solução onde eu faço io.emit('ping') a cada 30 segundos ou mais no front-end. Se houve uma desconexão, isso acaba acionando uma reconexão automática.

Aqui está o meu teste, tudo no Mac usando FF 10.0.2, Chrome 17.0.963.79 e Safari 5.1.2 (6534.52.7)
versão do socket.io = 0.8.7
versão do node.js = v0.6

O aplicativo cliente ouve todos os eventos io disponíveis. connect, connect, connect_failed, desconectar, reconectar, reconectar e reconnect_failed e efetuar logout no console

a situação .. estou conectado em todos os navegadores via websockets

agora desligo o wifi =>
FF: nenhum evento
Chrome: nenhum evento
Safari: evento = desconectar

mando um ping do FF e do Chrome para provocar um evento de desconexão =>
FF: nenhum evento
Chrome: nenhum evento

ligo o wifi novamente =>
FF: nenhum evento
Chrome: nenhum evento
Safari: evento = reconectar

eu envio mensagens entre os clientes =>
todos os 3 navegadores recebem as mensagens, então a reconexão automática parece funcionar, mesmo que os eventos não sejam disparados em ff e chrome

+1

+1

situação semelhante aqui. Tenho 2 dispositivos ipod touch (iOS 4.2.1) + galaxy note. galaxy note sempre pode detectar a desconexão do ipod touch enquanto o ipod não pode. Parece que o safari bloqueia os dados recebidos via websocket=[

Ainda com esse problema. Li alguns posts descrevendo o mesmo problema há um ano. Eu acho que tenho que contornar isso sozinho? ...

+1

+1

+1

Apenas um pequeno aviso, se você envolver o socket.io com o primus, esse problema será resolvido. Ele usa uma combinação de pacotes de ping e eventos online/offline para determinar esses problemas de conexão.

Consegui corrigir esse problema ajustando as configurações heartbeat timeout e heartbeat interval no servidor, que acredito ditar a pulsação do lado do cliente. Por exemplo, se você quiser que o cliente acione uma desconexão depois de fazer duas pulsações a cada 4 segundos e não receber uma resposta, configure da seguinte forma.

io.set('heartbeat timeout', 10) io.set('heartbeat interval', 4)

+1

2 anos e nenhuma solução? Por que o Safari é o único navegador que pode detectar a desconexão? FF e Chrome não seguem os padrões ??

+1

Obrigado @pwhisenhunt

@pwhisenhunt, mas, em alguns casos, a diminuição do batimento cardíaco causa outro problema.
Por exemplo, se a rede não for estável, o soquete será desconectado com muita frequência porque a pulsação é muito curta.
Espero que esse problema seja corrigido em breve

Sim, está correto. Obrigado por trazer isso à tona! Desculpe, devo ter esquecido isso no meu comentário anterior. Estou curioso se isso é corrigido em 1.0?

Por favor, perdoe qualquer erro ortográfico, esta mensagem foi enviada do meu iPhone.

Em 5 de junho de 2014, às 9h53, dev0x10 [email protected] escreveu:

@pwhisenhunt, mas, em alguns casos, a diminuição do batimento cardíaco causará outro problema.
Por exemplo, se a rede não for estável, o soquete será desconectado com muita frequência.
Espero que esse problema seja corrigido em breve


Responda a este e-mail diretamente ou visualize-o no GitHub.

Alguma solução para "desconectar evento não sendo acionado" ainda? Ou eu estou esquecendo de alguma coisa. Como a última solução sugerida por @pwhisenhunt não é tão confiável.

Estamos tendo esse mesmo problema na versão 1.3.6 do socket.io. O servidor do nó em nosso caso não está recebendo o evento de desconexão do cliente quando a rede sem fio é desligada ou o laptop é fechado.

+1

Estou enfrentando esse mesmo problema, usando a versão 1.4.3. Por que o assunto está encerrado?
Obrigado

Por favor, reabra este ticket, pois ainda não foi corrigido!
Eu estava olhando para o arquivo: https://github.com/socketio/socket.io-client/blob/master/lib/manager.js para descobrir se existe alguma opção para isso, e encontrei timeout que é 20 segundos por padrão.
Mas quando tentei mudar para 4 segundos, simplesmente não funcionou.

Tem o mesmo problema. Pode ser reproduzido no chrome sem desconexão real da Internet. Basta abrir Developer tools -> Network tab -> Escolha offline na caixa de seleção.

alguma novidade que possa funcionar?

Saaaame questão!

Por favor, reabra isso, não foi corrigido!

Concordo - isso ainda é um problema para mim também

Oi
eu uso esta solução e tudo bem para mim
var io = require('socket.io')(http, {'pingInterval': 2000, 'pingTimeout': 5000});
http://stackoverflow.com/a/31787022/2818627

Oi,
Ainda não encontrei uma boa solução para este problema. Desliguei minha conexão wifi, configurei o modo do navegador para offline, mas o evento de desconexão do socket.io não foi gerado. foi devido à conexão local?

Cumprimentos,
Suhas

+1

O mesmo problema. Esse problema precisa ser corrigido. Eu tenho isso com o Chrome 54.

+1

Eu tenho o mesmo problema, evento de desconexão do lado do cliente não detectado

  • Alguém tentou depurar com localStorage.debug='*' ?
  • Isso acontece apenas com o transporte websocket?
  • Qual versão do socket.io você está usando?

Acabei de testar com o exemplo de chat (socket.io 1.7.2 ; chrome ; linux):

image

Websocket é estabelecido:
23:09:37.709 => ping
23:09:37.934 => pong (resposta do servidor)
23:10:02.938 => ping
23:10:03.169 => pong
eu desligo o wi-fi
23:10:28.171 => ping
espere 60s => tempo limite => disconnect é demitido

25s sendo o valor padrão para pingInterval , 60s para pingTimeout ( ref )

Alguém pode confirmar/infirmar esse comportamento?

Além disso, se o servidor for morto, acho que o evento de desconexão seria acionado imediatamente, pois a conexão TCP subjacente é fechada.

Posso confirmar este comportamento: a desconexão é acionada no servidor e no cliente se um cabo de rede for desconectado. No entanto, também existe o caso em que o cliente é desconectado do servidor sem que nenhum evento seja acionado. As capturas de tela abaixo são de um cliente que não está mais emitindo para o servidor. Nenhum evento de desconexão foi disparado (no cliente ou no servidor). Observe que o cliente ainda parece estar recebendo pongs do servidor:

socketio

socketio2

socketio3

há também o caso em que o cliente é desconectado do servidor sem que nenhum evento seja disparado

Hmm, eu não entendo, como você sabe que o cliente é desconectado então?

Sim, "desconectado" provavelmente não é a palavra certa. O problema é que o cliente para de emitir para o servidor, embora ainda esteja recebendo pongs dele. Na última captura de tela que postei, socket.emit deveria ter sido chamado entre os eventos de ping pong, mas de alguma forma não foi.

Então, se entendi corretamente, o soquete ainda está emitindo pings/obtendo pongs, mas socket.emit() é descartado?

Você pode reproduzir facilmente? Ele está vinculado a um determinado navegador?

Ref: https://github.com/socketio/socket.io-client/blob/1.7.2/lib/socket.js#L155

  if (this.connected) {
    this.packet(packet);
  } else {
    this.sendBuffer.push(packet);
  }

Mas a única maneira de o sinalizador connected ser definido como false é aqui :

Socket.prototype.onclose = function (reason) {
  debug('close (%s)', reason);
  this.connected = false;
  this.disconnected = true;
  delete this.id;
  this.emit('disconnect', reason);
};

Portanto, não deve ser descartado aqui, já que você não obteve o evento disconnect . Caso contrário , se olharmos em

Socket.prototype.sendPacket = function (type, data, options, fn) {
  //...
  if ('closing' === this.readyState || 'closed' === this.readyState) {
    return;
  }

O sinalizador readyState é atualizado aqui .

Então, se eu entendi corretamente, o socket ainda está emitindo pings/obtendo pongs, mas socket.emit() é descartado?

Sim é isso. Vai tentar encontrar uma maneira de reproduzir.

@darrachequesne Acontece que meu próprio código estava bloqueando chamadas para socket.emit. Desculpas por ter desperdiçado seu tempo. Meu problema não era o mesmo que o problema deste tópico e certamente não era um problema com o socket.io.

@creole ótimo, obrigado!

Para todos os outros que marcaram com +1, meu comentário https://github.com/socketio/socket.io/issues/635#issuecomment -266880918 corrigiu (ou pelo menos explicou) seu problema?

De qualquer forma, talvez um valor padrão menor para pingTimeout ajudaria? Atualmente, no pior caso, deve-se esperar 85s (25000 (pingInterval) + 60000 (pingTimeout)) antes de obter um evento disconnect . Que tal um pingTimeout de 5s por padrão (que é o que @mbf5923 sugeriu,

Alterar tanto a configuração padrão pode levar a um comportamento inesperado em algumas implementações, mas concordo que diminuir pingTimeout para cerca de 30s seria mais proposital.

Experimentando esse problema também .. Alterar o intervalo de ping não parece confiável o suficiente na produção

Contanto que o bug não seja resolvido em breve e um propósito final do que precisamos é indicar se o usuário saiu, podemos estender nosso objeto de soquete usando middleware. Basicamente, precisamos estender o objeto socket com um usuário e uma sala em que o usuário está atualmente e depois que o usuário for desconectado, podemos usá-lo adequadamente conforme necessário. O código completo está disponível em: https://github.com/abitlog/retube/blob/master/server/utils/socket.js

  io.use(checkAuth);

  io.on('connection', function (socket) {
    socket.on('join chatroom', function (data) {
      const { id: room } = data;

      socket.join(room);

      io.to(room).emit('join chatroom', {
        user: socket.user,
        counter: socket.adapter.rooms[room].length
      });

      socket.currentChatroomId = room; // extend an object after user joins a room
    });

    socket.on('leave chatroom', function (data) { // this event will not be fired as long as client-side disconnect does not work
      const { id: room } = data;

      io.to(room).emit('leave chatroom', {
        user: socket.user,
        counter: socket.adapter.rooms[room] ? socket.adapter.rooms[room].length - 1 : null
      });

      socket.leave(room);
    });

    socket.on('disconnect', function () {
      const { currentChatroomId } = socket;

      io.to(currentChatroomId).emit('leave chatroom', { // we use currentChatroomId from our socket object to indicate the room user has left
        user: socket.user,
        counter: socket.adapter.rooms[currentChatroomId] ? socket.adapter.rooms[currentChatroomId].length  : null
      });

    });
  });

  function checkAuth(socket, next) {
    if (!socket.request.session.passport) {
      next(new AuthError(404));
      return;
    }

    socket.user = socket.request.session.passport.user;

    next();
  }

@abitlog Posso estar faltando algo aqui, mas seu caso de uso não está relacionado ao problema atual, certo?

Por favor, dê uma olhada no evento de desconexão .

@darrachequesne Eu investiguei o problema e parece que todos os eventos estão funcionando bem. É apenas no Chrome para mac (não notei isso na versão do Windows) levando muito tempo (aproximadamente 1 minuto) para acionar a desconexão. Eu tentei, claro, timeout e connect_error como tentativa de complementar disconnect como um evento irmão, mas não tive sorte.

@KamWis qual valor você está usando para pingTimeout/pingInterval ?

Acabei de passar por todas as minhas configurações de conexão novamente e devo ter cometido um erro de digitação em algum lugar. Quando defino pingTimeout e pingInterval no servidor, o cliente parece respeitar isso mesmo no Chrome. Se alguém estiver tendo problemas e quiser testar isso, ajuda definir localStorage.debug = 'engine.io-client:socket' no seu navegador. Isso fará com que as mensagens de ping/pong sejam exibidas no console.

Eu acho que o problema pode ser encerrado agora?

Sim, eu acredito que sim. Parece que tudo está funcionando conforme o esperado.

Eu posso detectar o evento de desconexão, mas demorou pelo menos 8 a 10 segundos.
você poderia me dizer por que isso acontece?

@Royalone-mobile, atualize os valores pingInterval / pingTimeout .

Eu resolvi este problema.
pode ser um bug do chrome. ainda está online quando configuramos a rede para o modo " offline " (quando o Google Chrome configura o modo de rede para offline, o websocket parece ser capaz de se comunicar também, e a rede não está realmente desconectado, você pode alternar para dois dispositivos e usar o método de desconexão física para verificar por si mesmo se esse é o motivo).
o jeito certo é usar socket.on('disconnect',function(){}) .
mas o valor padrão de pingInterval é 25000, o valor padrão de pingTimeout é 60000.é muito longo.
então precisamos definir pingInterval / pingTimeout para um valor pequeno.
(Na verdade, o evento de desconexão pode monitorar a desconexão do usuário, mas o uso indevido do Google Chrome enterrou o primeiro poço e, em seguida, o tempo de detecção de desconexão automática é relativamente longo e o segundo poço é enterrado, basta definir o pingInterval para um curto período de tempo Um ponto pode detectar rapidamente que o usuário está desconectado)

Esta página foi útil?
0 / 5 - 0 avaliações