web-dev-qa-db-fra.com

WebSockets dans Chrome et Firefox se déconnectant après une minute d'inactivité

J'ai constaté que les WebSockets dans Chrome et Firefox se déconnectent après exactement une minute d'inactivité. D'après ce que j'ai vu en ligne, j'étais prêt à blâmer les mandataires, certains paramètres du serveur ou autre chose, mais cela ne se produit pas dans IE ou Edge. Il semble que si les sockets sont déconnectés par le serveur après une minute d'inactivité, cela s'appliquerait à IE et à Edge autant qu'à Chrome et Firefox.

Quelqu'un sait pourquoi c'est comme cela? Est-ce documenté n'importe où? Je connais un moyen possible de l'arrêter en faisant un ping, mais je m'intéresse davantage à la raison pour laquelle cela se produit. Le code raison donné lors de la déconnexion est 1006, indiquant que le navigateur a fermé la connexion. Aucune erreur n'est générée et l'événement onerror pour le socket n'est pas déclenché.

Ce projet a été construit à l’adresse https://glitch.com/edit/#!/noiseless-helmet où vous pouvez tout voir et tout exécuter. La page cliente est servie ici: https://noiseless-helmet.glitch.me/

Voici ma page client:

<div id="div">
</div>
<script>
  let socket = new WebSocket("wss://noiseless-helmet.glitch.me/");
  socket.onmessage = function(event) {
    div.innerHTML += "<br>message " + new Date().toLocaleString() + " " + event.data;
  };
  socket.onopen = function (event) {
    div.innerHTML += "<br>opened " + new Date().toLocaleString();
    socket.send("Hey socket! " + new Date().toLocaleString());
  };
  socket.onclose = function(event) {
    div.innerHTML += "<br>socket closed " + new Date().toLocaleString();
    div.innerHTML += "<br>code: " + event.code;
    div.innerHTML += "<br>reason: " + event.reason;
    div.innerHTML += "<br>clean: " + event.wasClean;
  };
  socket.onerror = function(event) {
    div.innerHTML += "<br>error: " + event.error;
  };
</script>

Et voici le code de mon serveur Node.js:

var express = require('express');
var app = express();
app.use(express.static('public'));

let server = require('http').createServer(),
  WebSocketServer = require('ws').Server,
  wss = new WebSocketServer({ server: server });

app.get("/", function (request, response) {
  response.sendFile(__dirname + '/views/index.html');
});

let webSockets = [];
wss.on('connection', function connection(socket) {
  webSockets.Push(socket);
  webSockets.forEach((w) => { w.send("A new socket connected"); });
  socket.on('close', (code, reason) => {
    console.log('closing socket');
    console.log(code);
    console.log(reason);
    let i = webSockets.indexOf(socket);
    webSockets.splice(i, 1);
  });
});

server.on('request', app);
server.listen(process.env.PORT, function () {
  console.log('Your app is listening on port ' + server.address().port);
});
10
user12861

Il semble que si les sockets sont déconnectés par le serveur après une minute d'inactivité, cela s'appliquerait à IE et à Edge autant qu'à Chrome et Firefox.

Hmmm non. IE et Edge pourraient implémenter un paquet ping dans le cadre du protocole WebSocket.

_ { Le protocole WebSocket inclut la prise en charge d'un niveau de protocole ping que l'API JavaScript n'expose pas. C'est un peu plus bas que le ping au niveau utilisateur qui est souvent implémenté.

Ce trafic ping-pong réinitialise les temporisateurs de tous les intermédiaires du réseau (mandataires, équilibreurs de charge, etc.) - et toutes les connexions horaires pour marquer les connexions obsolètes en vue de leur fermeture (par exemple, le configuration Heroku multipliant les connexions à 55 secondes ).

La plupart des navigateurs font confiance au serveur pour implémenter la ping, qui est poli (car les serveurs doivent gérer leur charge et leur délai d'attente pour le ...

... mais c'est aussi légèrement frustrant, car les navigateurs n'ont aucune idée si une connexion a été perdue anormalement. C’est la raison pour laquelle de nombreux clients JavaScript implémentent un ping de niveau utilisateur (par exemple, un code JSON {event: "ping", data: {...}} ou un autre message d’événement "vide").

Quoi qu'il en soit, je voulais simplement souligner que votre hypothèse était incorrecte, que le délai d'attente était toujours écoulé et que la différence de comportement du navigateur était probablement liée aux navigateurs eux-mêmes.

Pour plus de détails sur les délais d’exécution par défaut de nginx (lors de l’exploration de connexions WebSocket par proxy), vous pouvez lire la réponse de @ Hendry.

3
Myst

La spécification du protocole WebSocket définit des trames Ping et Pong pouvant être utilisées pour la détection de l'état du réseau permanent, actif et permanent. Ping signifie que le client/serveur envoie un iq pour informer le serveur/client de l'autre côté que maintenir la connexion en vie et que l'autre côté enverra un accusé de réception avec pong ayant les mêmes données utiles.

Vous pouvez également définir un délai d'attente lorsque le navigateur cesse de répondre ou est considéré comme mort.

lire plus: http://vunse.blogspot.in/2014/04/websocket-ping-pong.html

4
Sakshi Nagpal

Autant que je sache, en recherchant cela, cela est causé par le dépassement de délai de WebSocket sur une période de temps pendant laquelle aucune donnée n'est envoyée. C'est probablement par navigateur. 

Vous pouvez utiliser des pings pour résoudre ce problème ou simplement vous reconnecter lorsque vous devez utiliser le socket à nouveau.

Il est logique de ne pas laisser les sockets ouverts quand ils ne sont pas utilisés côté serveur ou côté navigateur. Par exemple, Chrome a une limite de nombre de connexions ouvertes, si la limite est de 64 connexions et que vous avez ouvert 64 onglets (ce qui est très probable pour moi car j’ai toujours des charges d’onglets ouverts) et serveur, plus aucune connexion n’a pu être établie (une chose semblable m’est arrivée une fois, quand j’ai manqué de sockets disponibles dans Chrome, drôle).

Il y a proxy_read_timeout ( http://nginx.org/r/proxy_read_timeout ) qui s'applique également aux connexions WebSocket. Vous devez cogner si votre back-end n’envoie rien pendant longtemps. Alternativement, vous pouvez configurer votre backend pour envoyer websocket pingez les cadres périodiquement pour réinitialiser le délai (et vérifiez si la connexion est toujours active).

https://forum.nginx.org/read.php?2,236382,236383#msg-236383

Web Sockets a un délai d'inactivité de 60 secondes: si vous n'utilisez pas de pulsation ou similaire via des cadres ping et pong, le socket suppose que l'utilisateur a fermé la page et le ferme pour économiser les ressources.

https://www.codeproject.com/Questions/1205863/Websocket-is-closed-after-min

https://github.com/tornadoweb/tornado/issues/1070

4
Hendry