javascript - ejemplo - websocket nodejs
Manejo de pérdida de conexión con websockets (4)
Tienes que añadir el método de ping pong.
Cree un código en el servidor cuando reciba __ping__ enviar __pong__ atrás
El código de JavaScript está abajo.
function ping() {
ws.send(''__ping__'');
tm = setTimeout(function () {
/// ---connection closed ///
}, 5000);
}
function pong() {
clearTimeout(tm);
}
websocket_conn.onopen = function () {
setInterval(ping, 30000);
}
websocket_conn.onmessage = function (evt) {
var msg = evt.data;
if (msg == ''__pong__'') {
pong();
return;
}
//////-- other operation --//
}
Recientemente configuré un servidor WebSocket local que funciona bien, sin embargo, tengo algunos problemas para entender cómo debo manejar una pérdida repentina de conexión que ni el cliente ni el servidor iniciaron intencionalmente, es decir: el servidor pierde la alimentación, los cables Ethernet retirado, etc. Necesito que el cliente sepa si la conexión se ha perdido en unos 10 segundos.
Lado del cliente, la conexión es simplemente:
var websocket_conn = new WebSocket(''ws://192.168.0.5:3000'');
websocket_conn.onopen = function(e) {
console.log(''Connected!'');
};
websocket_conn.onclose = function(e) {
console.log(''Disconnected!'');
};
Puedo activar manualmente la desconexión de conexión que funciona bien,
websocket_conn.close();
Pero si simplemente extraje el cable Ethernet de la parte posterior de la computadora, o deshabilito la conexión, no se llama al onclose
. He leído en otra publicación que eventualmente se llamaría cuando TCP detecte la pérdida de conectividad , pero no es lo que necesito ya que el valor predeterminado para Firefox es de 10 minutos, y realmente no quiero ir Alrededor de cientos de computadoras about:config
cambiando este valor. La única otra sugerencia que he leído es utilizar un método de estilo de sondeo keep-alive de ''ping / pong'' que parezca contrario a la idea de websockets.
¿Hay una manera más fácil de detectar este tipo de comportamiento de desconexión? ¿Las publicaciones antiguas que estoy leyendo todavía están actualizadas desde un punto técnico, y el mejor método sigue siendo el estilo ''ping / pong''?
El protocolo websocket define marcos de control para ping y pong . Básicamente, si el servidor envía un ping, el navegador responderá con un pong, y debería funcionar también al revés. Probablemente el servidor WebSocket que usa los implementa, y puede definir un tiempo de espera en el que el navegador debe responder o ser considerado muerto. Esto debería ser transparente para su implementación tanto en el navegador como en el servidor.
Puede usarlos para detectar conexiones medio abiertas: http://blog.stephencleary.com/2009/05/detection-of-half-open-dropped.html
También relevante: WebSockets ping / pong, ¿por qué no TCP keepalive?
Esta fue la solución que terminé haciendo, la cual parece funcionar bien por el momento, es completamente específica para la configuración de mi proyecto y se basa en los criterios que no se mencionaron originalmente en mi pregunta, pero podrían ser útiles para otra persona. Si sucede que están haciendo lo mismo.
La conexión al servidor websocket se produce dentro de un complemento de Firefox y, de forma predeterminada, la configuración TCP de Firefox tiene un tiempo de espera de 10 minutos. Puede ver detalles adicionales con about:config
y buscar TCP.
Los complementos de Firefox pueden acceder a estos parámetros.
var prefs = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService);
y también cambie estos parámetros especificando la rama y la preferencia junto con el nuevo valor
prefs.getBranch("network.http.tcp_keepalive.").setIntPref(''long_lived_idle_time'', 10);
Así que ahora, cualquier computadora con el complemento instalado tiene un tiempo de espera de 10 segundos para las conexiones TCP. Si se pierde la conexión, se onclose
evento onclose
que muestra una alerta y también intenta restablecer la conexión
websocket_conn.onclose = function (e) {
document.getElementById(''websocket_no_connection'').style.display = ''block'';
setTimeout(my_extension.setup_websockets, 10000);
};
Usé la idea de ping / pong y funciona muy bien. Aquí está mi implementación en mi archivo server.js:
var SOCKET_CONNECTING = 0;
var SOCKET_OPEN = 1;
var SOCKET_CLOSING = 2;
var SOCKET_CLOSED = 3;
var WebSocketServer = require(''ws'').Server
wss = new WebSocketServer({ port: 8081 });
//Broadcast method to send message to all the users
wss.broadcast = function broadcast(data,sentBy)
{
for (var i in this.clients)
{
if(this.clients[i] != sentBy)
{
this.clients[i].send(data);
}
}
};
//Send message to all the users
wss.broadcast = function broadcast(data,sentBy)
{
for (var i in this.clients)
{
this.clients[i].send(data);
}
};
var userList = [];
var keepAlive = null;
var keepAliveInterval = 5000; //5 seconds
//JSON string parser
function isJson(str)
{
try {
JSON.parse(str);
}
catch (e) {
return false;
}
return true;
}
//WebSocket connection open handler
wss.on(''connection'', function connection(ws) {
function ping(client) {
if (ws.readyState === SOCKET_OPEN) {
ws.send(''__ping__'');
} else {
console.log(''Server - connection has been closed for client '' + client);
removeUser(client);
}
}
function removeUser(client) {
console.log(''Server - removing user: '' + client)
var found = false;
for (var i = 0; i < userList.length; i++) {
if (userList[i].name === client) {
userList.splice(i, 1);
found = true;
}
}
//send out the updated users list
if (found) {
wss.broadcast(JSON.stringify({userList: userList}));
};
return found;
}
function pong(client) {
console.log(''Server - '' + client + '' is still active'');
clearTimeout(keepAlive);
setTimeout(function () {
ping(client);
}, keepAliveInterval);
}
//WebSocket message receive handler
ws.on(''message'', function incoming(message) {
if (isJson(message)) {
var obj = JSON.parse(message);
//client is responding to keepAlive
if (obj.keepAlive !== undefined) {
pong(obj.keepAlive.toLowerCase());
}
if (obj.action === ''join'') {
console.log(''Server - joining'', obj);
//start pinging to keep alive
ping(obj.name.toLocaleLowerCase());
if (userList.filter(function(e) { return e.name == obj.name.toLowerCase(); }).length <= 0) {
userList.push({name: obj.name.toLowerCase()});
}
wss.broadcast(JSON.stringify({userList: userList}));
console.log(''Server - broadcasting user list'', userList);
}
}
console.log(''Server - received: %s'', message.toString());
return false;
});
});
Aquí está mi archivo index.html:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>Socket Test</title>
</head>
<body>
<div id="loading" style="display: none">
<p align="center">
LOADING...
</p>
</div>
<div id="login">
<p align="center">
<label for="name">Enter Your Name:</label>
<input type="text" id="name" />
<select id="role">
<option value="0">Attendee</option>
<option value="1">Presenter</option>
</select>
<button type="submit" onClick="login(document.getElementById(''name'').value, document.getElementById(''role'').value)">
Join
</button>
</p>
</div>
<div id="presentation" style="display: none">
<div class="slides">
<section>Slide 1</section>
<section>Slide 2</section>
</div>
<div id="online" style="font-size: 12px; width: 200px">
<strong>Users Online</strong>
<div id="userList">
</div>
</div>
</div>
<script>
function isJson(str) {
try {
JSON.parse(str);
}
catch (e) {
return false;
}
return true;
}
var ws;
var isChangedByMe = true;
var name = document.getElementById(''name'').value;
var role = document.getElementById(''role'').value;
function init()
{
loading = true;
ws = new WebSocket(''wss://web-sockets-design1online.c9users.io:8081'');
//Connection open event handler
ws.onopen = function(evt)
{
ws.send(JSON.stringify({action: ''connect'', name: name, role: role}));
}
ws.onerror = function (msg) {
alert(''socket error:'' + msg.toString());
}
//if their socket closes unexpectedly, re-establish the connection
ws.onclose = function() {
init();
}
//Event Handler to receive messages from server
ws.onmessage = function(message)
{
console.log(''Client - received socket message: ''+ message.data.toString());
document.getElementById(''loading'').style.display = ''none'';
if (message.data) {
obj = message.data;
if (obj.userList) {
//remove the current users in the list
userListElement = document.getElementById(''userList'');
while (userListElement.hasChildNodes()) {
userListElement.removeChild(userListElement.lastChild);
}
//add on the new users to the list
for (var i = 0; i < obj.userList.length; i++) {
var span = document.createElement(''span'');
span.className = ''user'';
span.style.display = ''block'';
span.innerHTML = obj.userList[i].name;
userListElement.appendChild(span);
}
}
}
if (message.data === ''__ping__'') {
ws.send(JSON.stringify({keepAlive: name}));
}
return false;
}
}
function login(userName, userRole) {
if (!userName) {
alert(''You must enter a name.'');
return false;
}
//set the global variables
name = userName;
role = userRole;
document.getElementById(''loading'').style.display = ''block'';
document.getElementById(''presentation'').style.display = ''none'';
document.getElementById(''login'').style.display = ''none'';
init();
}
</script>
</body>
</html>
Aquí hay un enlace a la caja de arena de la nube 9 si quiere probarlo usted mismo: https://ide.c9.io/design1online/web-sockets