2010-09-23 19 views
54

Estoy usando un socket web usando PHP5 y el navegador Chrome como cliente. He tomado el código del sitio http://code.google.com/p/phpwebsocket/.Reconexión de Cliente cuando el servidor se reinicia en WebSocket

Ejecuto el servidor y el cliente también está conectado. Yo también puedo chatear Ahora cuando reinicio el servidor (eliminándolo e iniciándolo de nuevo), el cliente obtiene la información desconectada, pero no se vuelve a conectar automáticamente con el servidor cuando envío el mensaje.

¿Cómo lograr esto? Al igual que cuando obtengo la información desconectada, ¿debo revisarla y enviarla a JavaScript para actualizar la página o volver a conectar?

Respuesta

95

Cuando el servidor se reinicia, la conexión Web Socket se cierra, por lo que se desencadena el evento JavaScript onclose. Aquí hay un ejemplo que intenta volver a conectar cada cinco segundos.

function start(websocketServerLocation){ 
    ws = new WebSocket(websocketServerLocation); 
    ws.onmessage = function(evt) { alert('message received'); }; 
    ws.onclose = function(){ 
     // Try to reconnect in 5 seconds 
     setTimeout(function(){start(websocketServerLocation)}, 5000); 
    }; 
} 
+0

que estaba teniendo este mismo problema y su solución funcionó muy bien. Gracias! –

+1

Debería usar una función anónima aquí: 'function() {start (websocketServerLocation)}' en lugar de una cadena, por lo que no activa un 'eval()' –

+2

Espero que haya una manera más elegante, sin construir una nueva objeto y definición de acciones de evento ... – ciembor

29

La solución dada por Andrew no funciona a la perfección porque, en caso de pérdida de conexión, el servidor podría enviar varios eventos cercanos.

En ese caso, configurará varios setTimout. La solución dada por Andrew solo puede funcionar si el servidor está listo antes de cinco segundos.

Entonces, basado en la solución Andrés, vuelto a trabajar, he hecho uso de setInterval fijar el ID al objeto de ventana (de esa manera que esté disponible "en todas partes"):

var timerID=0; 

var socket; 

/* Initiate what has to be done */ 

socket.onopen=function(event){ 
/* As what was before */ 
if(window.timerID){ /* a setInterval has been fired */ 
    window.clearInterval(window.timerID); 
    window.timerID=0; 
} 
/* ... */ 
} 

socket.onclose=function(event){ 
    /* ... */ 
if(!window.timerID){ /* Avoid firing a new setInterval, after one has been done */ 
    window.timerID=setInterval(function(){start(websocketServerLocation)}, 5000); 
} 
/* That way, setInterval will be fired only once after losing connection */ 
/* ... */ 
} 
16

He estado usando este Patten por un tiempo para JavaScript puro y vainilla, y admite algunos casos más que las otras respuestas.

document.addEventListener("DOMContentLoaded", function() { 

    'use strict'; 

    var ws = null; 

    function start(){ 

    ws = new WebSocket("ws://localhost/"); 
    ws.onopen = function(){ 
     console.log('connected!'); 
    }; 
    ws.onmessage = function(e){ 
     console.log(e.data); 
    }; 
    ws.onclose = function(){ 
     console.log('closed!'); 
     //reconnect now 
     check(); 
    }; 

    } 

    function check(){ 
    if(!ws || ws.readyState == 3) start(); 
    } 

    start(); 

    setInterval(check, 5000); 


}); 

Esto volverá a intentar tan pronto como el servidor cierra la conexión, y se comprobará la conexión para asegurarse de que depende de cada 5 segundos también.

Por lo tanto, si el servidor no está funcionando cuando esto se ejecuta o en el momento del evento onclose, la conexión seguirá apareciendo cuando vuelva a estar en línea.

NOTA: El uso de este script no le permitirá dejar de intentar abrir una conexión ... ¿pero creo que eso es lo que quiere?

+5

Solo cambiaría: función check() { if (! Ws || ws.readyState === WebSocket.CLOSED) start(); } – dieresys

+0

Este enfoque, más una técnica de mantener vivo descrito [aquí] (http://www.jstips.co/en/javascript/working-with-websocket-timeout/), parece funcionar bien para mí. – Peter

3

A continuación se muestran los códigos que he utilizado en mi proyecto que trabajan al 100%.

  1. Ponga todo el código websocket dentro de la función init.
  2. Dentro de la devolución de llamada onclose, vuelva a llamar a init.
  3. Finalmente, llame a la función init dentro de la función de preparación de documentos.

var name = sessionStorage.getItem ('name');

wsUri = "ws://localhost:8080"; 
var websocket; 
$(function() { 
    init(); 
    $("#chat_text_box").on("keypress", function(e) {   
     if (e.keyCode == 13) { //For Enter Button  
      e.preventDefault(); 
      var mymessage = $('#chat_text_box').val();    
      if(mymessage){ 
       var msg = { type: 'chat_text', data : { name:name, msg:mymessage } };     
       console.log(msg); 
       websocket.send(JSON.stringify(msg)); 
       $('#chat_text_box').val(''); 
      }    
      return false;      
     }   
    });  
});  
function init() { 
    websocket = new WebSocket(wsUri);  
    websocket.onopen = function(ev) { /*connection is open */ } 
    websocket.onmessage = function(ev) {   
     var data = JSON.parse(ev.data); //PHP sends Json data   
     var type = data.type;//alert(JSON.stringify(data)); 
     switch(type) { 
      case "chat_text": 
       var text = "<div><span class='user'>"+data.data.sender_name+" : </span><span class='msg'>"+data.data.msg+"</span></div>"; 
       $('#chat-messages').append(text); 
       break;    
      default: 
       break; 

     }   

    };  
    websocket.onerror = function(ev){}; 
    websocket.onclose = function(ev) { init(); }; 
} 
21

ReconnectingWebSocket

GitHub alberga una pequeña biblioteca JavaScript que decora la API WebSocket para proporcionar una conexión WebSocket que se vuelva a conectar automáticamente si la conexión se interrumpe.

La biblioteca minificada con compresión gzip tiene menos de 600 bytes.

El repositorio oficial está disponible aquí:

https://github.com/joewalnes/reconnecting-websocket

inundación servidor

Si un gran número de clientes están conectados al servidor cuando se reinicia. Puede valer la pena administrar los tiempos de reconexión de los clientes mediante el uso de un algoritmo de retroceso exponencial.

El algoritmo funciona así:

  1. para k intentos, generan un intervalo de tiempo aleatorio entre 0 y 2^k - 1,
  2. Si usted es capaz de volver a conectar, reiniciar K a 1,
  3. Si la reconexión falla, k aumenta en 1 y el proceso se reinicia en el paso 1,
  4. Para truncar el intervalo máximo, cuando se alcanza un determinado número de intentos k, k deja de aumentar después de cada intento.

Referencia:

http://blog.johnryding.com/post/78544969349/how-to-reconnect-web-sockets-in-a-realtime-web-app

ReconnectingWebSocket reconexiones no maneja mediante el uso de este algoritmo.

+3

https://github.com/gamestdio/websocket.js usa un retroceso exponencial – vgoklani

+0

Gran respuesta, especialmente porque menciona el riesgo de una gran carga del servidor una vez que el servidor cierra las conexiones del socket web, y todos los clientes (que podrían ser cientos o miles) intentan reconectarse al mismo tiempo. En lugar de retroceso exponencial, también podría aleatorizar la demora como entre 0 y 10 segundos. Eso extenderá la carga en el servidor también. –

0

que no puedo comentar, pero los siguientes:

var socket; 

const socketMessageListener = (event) => { 
    console.log(event.data); 
}; 

const socketOpenListener = (event) => { 
    console.log('Connected'); 
    socket.send('hello'); 
}; 

const socketCloseListener = (event) => { 
    if (socket) { 
    console.error('Disconnected.'); 
    } 
    socket = new WebSocket('ws://localhost:8080'); 
    socket.addEventListener('open', socketOpenListener); 
    socket.addEventListener('message', socketMessageListener); 
    socket.addEventListener('close', socketCloseListener); 
}; 

socketCloseListener(); 

// for testing 
setTimeout(()=>{ 
    socket.close(); 
},5000); 

Plus https://www.npmjs.com/package/back ya es lo suficientemente bueno :)

Cuestiones relacionadas