Question Comment trouver le temps de réponse (latence) d'un client dans NodeJS avec des sockets (socket.io)?


J'essaie de créer un jeu multijoueur avec NodeJS et je veux synchroniser l'action entre les clients.

Quelle serait la meilleure façon de trouver la latence (le temps qu’une demande prend pour revenir sur le client) entre le client et le serveur?

Ma première idée était que le client n ° 1 pouvait envoyer un horodatage avec une demande, donc quand le client n ° 2 recevra l'action du client n ° 1, il ajustera sa vitesse d'action pour supprimer le délai de la demande. Mais le problème est que peut-être la date et l'heure système des deux clients ne sont pas identiques, il n'est donc pas possible que deux connaissent le délai de la bobine à la demande du client n ° 1.

L'autre solution consistait à utiliser l'horodatage du serveur, mais maintenant, comment puis-je connaître la latence d'un client?


20
2017-11-01 17:12


origine


Réponses:


Je vais supposer que vous utilisez WebSockets ou Socket.IO puisque vous implémentez un jeu où la latence est importante (et vous l’avez marqué en tant que tel).

Je pense que le serveur devrait probablement mesurer et suivre cela pour chaque client.

Vous souhaitez probablement implémenter une action ping que le serveur peut demander au client. Dès que le client reçoit la demande, il renvoie une réponse au serveur. Le serveur divise ensuite par 2 et met à jour la latence pour ce client. Vous voulez probablement que le serveur fasse cela périodiquement avec chaque client et qu'il y ait probablement la moyenne des derniers pour ne pas avoir un comportement étrange dû à des pics soudains mais temporaires.

Ensuite, lorsqu'un message d'un client doit être envoyé (ou diffusé) à un autre client, le serveur peut ajouter la latence de client1 à la latence du client2 et la communiquer comme décalage de latence à client2. client2 saura alors que l'événement sur client1 s'est produit il y a plusieurs millisecondes.

Une autre raison de faire cela sur le serveur est que certains horodatages Javascript du navigateur sont inexacts: http://ejohn.org/blog/accuracy-of-javascript-time/. Je pense que les horodatages node.js sont tout aussi précis (ou plus) que la version V8 (qui est l'une des rares précises).


20
2017-11-01 19:07



Aperçu:

Une fois la connexion socket.io établie, vous créez une nouvelle Date objet sur le client, appelons-le startTime. C'est ton heure initiale avant de faire une demande au serveur. Vous émettez alors un ping événement du client. La convention de nommage vous appartient totalement. Pendant ce temps, le serveur devrait écouter ping événement, et quand il reçoit le ping, il émet immédiatement un pong un événement. Le client attrape alors le pong un événement. À ce moment, vous voulez créer un autre objet de date qui représente Date.now(). Donc, à ce stade, vous avez deux objets de date - la date initiale avant de faire une demande au serveur, et un autre objet de date après avoir fait une demande au serveur et il a répondu. Soustraire le startTime de l'heure actuelle et vous avez le latency.

Client

var socket = io.connect('http://localhost');
var startTime;

setInterval(function() {
  startTime = Date.now();
  socket.emit('ping');
}, 2000);

socket.on('pong', function() {
  latency = Date.now() - startTime;
  console.log(latency);
});

Serveur

io.sockets.on('connection', function (socket) {
  socket.on('ping', function() {
    socket.emit('pong');
  });
});

Aussi disponible en tant que Github Gist.


16
2018-01-10 23:45



Ce que je fais habituellement pour envoyer un horodatage avec demande:

  1. Sur le client, créez un new Date() et envoyer timestamp: date.getTime() au serveur, avec chaque requête JSON.
  2. Sur le serveur, à la réception d'une demande, mettez un processed: (new Date()).getTime() dans l'objet.
  3. Traiter la demande
  4. Sur la réponse, mettez le timestamp à partir de la requête, et un nouveau champ traité: processed: (new Date()).getTime() - req.processed qui contient maintenant le nombre de millisecondes nécessaires au traitement de la demande.
  5. Sur le client, en recevant une réponse, prenez le timestamp (qui est le même qui a été envoyé sur pt 1) et le soustraire de l'heure actuelle, et soustraire le temps de traitement (processed), et il y a votre "vrai" temps de ping en millisecondes.

Je pense que vous devriez toujours inclure l'heure de la demande et de la réponse dans le temps de réponse, même s'il y a une communication à sens unique. C'est parce que c'est la signification standard derrière "ping time" et "latency". Et si c'est une communication à sens unique et que la latence n'est que la moitié du temps de ping réel, c'est juste une "bonne chose".


4
2017-11-03 11:58



Voici mon script très rapide et sale pour tester le ping ... http: // votre serveur: 8080 dans votre navigateur et regardez la console (terminal ssh pour moi).

var http = require('http');
var io = require('socket.io');

server = http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/html'});
  res.write('<html>\n');
  res.write('  <head>\n');
  res.write('    <title>Node Ping</title>\n');
  res.write('    <script src="/socket.io/socket.io.js"></script>\n');
  res.write('    <script>\n');
  res.write('        var socket = new io.Socket();\n');
  res.write('        socket.on("connect",function(){ });\n');
  res.write('        socket.on("message",function(){ socket.send(1); });\n');
  res.write('        socket.connect();\n');
  res.write('    </script>\n');
  res.write('  </head>\n');
  res.write('  <body>\n');
  res.write('    <h1>Node Ping</h1>\n');
  res.write('  </body>\n');
  res.write('</html>\n');
  res.end();
});
server.listen(8080);

console.log('Server running at http://127.0.0.1:8080/');

var socket = io.listen(server);

socket.on('connection',function(client){
  var start = new Date().getTime();
  client.send(1);
  client.on('message',function(message){ client.send(1);  console.log( new Date$
  client.on('disconnect',function(){});
});

Je suis très curieux à ce sujet car il semble que mes pings soient assez élevés (200-400ms aller / retour) sur de grandes boîtes vps avec des ressources dédiées en Californie et en New Jersey. (Je suis sur la côte est) Je parie qu'il y a juste beaucoup de latence sur les boites vps, car elles servent autant de trafic?

Ce qui me fait comprendre, c'est qu'un ping régulier depuis le terminal Linux du même client vers le même serveur est en moyenne de 11 ms, soit un facteur 10 de moins ... Je fais quelque chose de mal ou est quelque chose de lent avec socket.js /. io / websockets?


1
2017-11-03 12:41



Après avoir lu toutes ces réponses ...

... je n'étais toujours pas satisfait. J'ai visité les documents officiels et bien, eh bien, la solution est déjà intégrée.

Vous avez juste besoin de l'implémenter - jetez un coup d'œil au mien:

Client

// (Connect to socket).

var latency = 0;

socket.on('pong', function(ms) {
    latency = ms;

    console.log(latency);
});

// Do cool things, knowing the latency...

Serveur

var server = require('http').Server(app);

// "socket.io": "^1.7.1"
// Set pingInterval to whatever you want - 'pong' gets emitted for you!
var io = require('socket.io')(server, {pingInterval: 5000});

0
2017-07-20 13:43



Lire d'abord - En raison de questions répétées sur la raison pour laquelle cela est censé fonctionner, permettez-moi de clarifier un peu.

  • La fonction de rappel client est exécuté sur le client, c'est pourquoi il a accès à la fermeture, y compris le start variable contenant l’horodatage. C'est l'argument ack () dans socket.io.
  • Le serveur ne peut naturellement pas appeler une fonction arbitraire sur le client et accéder à la fermeture de la fonction. Mais socket.io permet de définir une fonction de rappel, qui semble être exécuté par le serveur, mais cela ne fait que passer les arguments de la fonction via le socket Web, et le client appelle alors le rappel.

Que se passe-t-il ci-dessous (veuillez vérifier le code exemple!):

  1. Client stocke l'horodatage actuel 1453213686429 dans start
  2. Le client envoie un ping événement au serveur et attend une réponse
  3. Le serveur répond à l'événement ping avec "Veuillez appeler votre rappel avec des arguments vides"
  4. Le client reçoit la réponse et les appels clientCallback avec des arguments vides (vérifiez le code démo si vous voulez voir des arguments)
  5. clientCallback prend à nouveau l'horodatage actuel sur le client, par exemple. 1453213686449, et sait que 20 ms ont passé depuis l'envoi de la demande.

Imagine le druide (client) tenir un chronomètre et appuyer sur le bouton lorsque le messager (un événement) commence à courir, et le repoussant quand le messager arrive avec son parchemin (arguments de fonction). Le druide lit alors le parchemin et ajoute les noms des ingrédients à sa recette de potion et prépare la potion. (rappeler)

Ok, oublie le paragraphe précédent, je suppose que tu as compris.


Bien que la question ait déjà reçu une réponse, voici une courte mise en œuvre pour vérifier le RTT avec socket.io:

Client

var start = Date.now();
this.socket.emit( 'ping', function clientCallback() {
    console.log( 'Websocket RTT: ' + (Date.now() - start) + ' ms' );
} );

Serveur

socket.on( 'ping', function ( fn ) {
    fn(); // Simply execute the callback on the client
} );

Code de démo

Code de démonstration en tant que module de noeud: socketIO-callback.tgz Configurez-le et lancez-le avec

npm install
node callback.js

puis naviguez jusqu'à http: // localhost: 5060


0
2018-03-14 13:05