web-dev-qa-db-fra.com

Comment implémenter une requête Ping / Pong pour une connexion webSocket active en javascript?

J'utilise websocket en javascript. Mais la connexion se ferme après une minute.

Je me demande quelque chose:

1- Websocket ne fournit-il pas naturellement des messages Ping/Pong pour ne pas fermer la connexion? Je pense qu'il le faut. Sinon, quelle est la différence entre websocket et TCP?

2- Si je dois envoyer les messages ping/pong, comment le message ping est-il envoyé? Que dois-je faire? L'objet WebSocket fournit-il une méthode ping? Ou dois-je appeler une méthode en tant que websocket.send ("ping")? J'utilise l'objet NaturalS WebSocket en javascipt.

3- Le serveur doit-il répondre aux requêtes Ping avec Pong? Cela devrait-il être mis en œuvre séparément côté serveur?

Remarque: Désolé pour mon anglais.

6
Qwer Sense

À ce stade, les pulsations sont normalement implémentées côté serveur: il n'y a pas grand-chose à faire du côté client.

Cependant, si le serveur continue de tuer votre connexion socket et que vous n'avez aucun contrôle sur celle-ci, il est possible que le client envoie des données arbitraires au websocket sur un intervalle:

let socket = null;

function connect_socket() {
  socket = new WebSocket(ws_url);
  socket.on("close", connect_socket); // <- rise from your Grave!
  heartbeat();
}

function heartbeat() {
  if (!socket) return;
  if (socket.readyState !== 1) return;
  socket.send("heartbeat");
  setTimeout(heartbeat, 500);
}

connect_socket();

Je recommande fortement d'essayer de trier ce qui se passe du côté serveur, plutôt que d'essayer de le contourner sur le client.

4
ouni

Oui, il y a des cadres ping/pong dans les websockets. Voici un exemple utilisant le module ws, où le serveur lance la requête ping:

const http = require('http');
const ws = require('ws');

const server = http.createServer(function(req_stream_in, res_stream_out) {
  // handle regular HTTP requests here
});
const webSocketServer = new ws.Server({
  path: "/websocket",
  server: server
});

const connected_clients = new Map();

webSocketServer.on('connection', function connection(ws_client_stream) {
  // NOTE: only for demonstration, will cause collisions.  Use a UUID or some other identifier that's actually unique.
  const this_stream_id = Array.from(connected_clients.values()).length;

  // Keep track of the stream, so that we can send all of them messages.
  connected_clients.set(this_stream_id, ws_client_stream);

  // Attach event handler to mark this client as alive when pinged.
  ws_client_stream.is_alive = true;
  ws_client_stream.on('pong', () => { ws_client_stream.is_alive = true; });

  // When the stream is closed, clean up the stream reference.
  ws_client_stream.on('close', function() {
    connected_clients.delete(this_stream_id);
  });
});

setInterval(function ping() {
  Array.from(connected_clients.values()).forEach(function each(client_stream) {
    if (!client_stream.is_alive) { client_stream.terminate(); return; }
    client_stream.is_alive = false;
    client_stream.ping();
  });
}, 1000);
4
ouni

Mozilla documente une convention dédiée au ping/pong.

À tout moment après la prise de contact, le client ou le serveur peuvent choisir d'envoyer un ping à l'autre partie. Lorsque le ping est reçu, le destinataire doit renvoyer un pong dès que possible. Vous pouvez l'utiliser pour vous assurer que le client est toujours connecté, par exemple.

Un ping ou un pong n'est qu'un cadre normal, mais c'est un cadre de contrôle. Les pings ont un opcode de 0x9 et les pongs ont un opcode de 0xA. Lorsque vous obtenez un ping, renvoyez un pong avec les mêmes données utiles que le ping (pour les pings et les pongs, la longueur maximale de la charge utile est de 125). Vous pouvez également obtenir un pong sans jamais envoyer de ping; ignorez cela si cela se produit.

Si vous avez obtenu plus d'un ping avant d'avoir la possibilité d'envoyer un pong, vous n'en envoyez qu'un seul.

Voir: https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_servers#Pings_and_Pongs_The_Heartbeat_of_WebSockets

Trouvez une discussion plus approfondie sur le ping/pong du côté du navigateur ici: Envoi du cadre ping/pong du websocket depuis le navigateur

Plus précisément, lisez le Websocket RFC 6455 sur le ping/pong.

1
Pim Heijden

Dans la solution d'ouni, heartbeat () n'intervenait pas. Cela fonctionne quand il est placé dans un événement open comme ceci:

let socket = null;

function connect_socket() {
  socket = new WebSocket(ws_url);
  socket.on("close", connect_socket); // <- rise from your Grave!
  socket.on("open", heartbeat); // heartbeat when the socket is open
}

function heartbeat() {
  if (!socket) return;
  if (socket.readyState !== 1) return;
  socket.send("heartbeat");
  setTimeout(heartbeat, 500);
}

connect_socket();
0
upteryx