Comment puis-je trouver le temps de réponse (latence) d'un client NodeJS avec les sockets (socket.io)?

StackOverflow https://stackoverflow.com/questions/4071258

Question

Je suis en train 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 le temps de latence (le temps qu'une prise de demande de revenir au client) entre le client et le serveur?

Ma première idée était que le client n ° 1 pourrait envoyer un horodatage à la demande est, de sorte que lorsque le client # 2 recevra l'action du client n ° 1, il ajustera est la vitesse d'action pour éliminer le retard de la demande. Mais le problème est que peut-être le temps de la date du système des deux clients ne sont pas identiques, de sorte qu'il est impossible de deux savoir le retard de la bobine à la demande du client n ° 1.

L'autre solution était d'utiliser l'horodatage du serveur, mais maintenant comment puis-je connaître le temps d'attente d'un client?

Était-ce utile?

La solution

Je vais supposer que vous utilisez WebSockets ou Socket.IO puisque vous mettent en œuvre un jeu où la latence des questions (et vous en tant que tel il étiqueté).

Je pense que le serveur devrait probablement mesurer et de garder une trace de cette opération pour chaque client.

Vous voulez sans doute mettre en œuvre une sorte d'action ping que le serveur peut demander du 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 le temps d'attente pour ce client. Vous voulez sans doute le serveur pour le faire périodiquement avec chaque client et probablement en moyenne ces dernières afin que vous ne soyez pas un comportement étrange de pics soudains, mais temporaires.

Alors, quand il y a un message d'un client qui doit être envoyé (ou de diffusion) à un autre client, le serveur peut ajouter la latence de client1 à la latence de client2 et de communiquer ce que le temps d'attente décalage client2 dans le cadre du message. client2 saura alors que l'événement sur client1 est arrivé il y a que plusieurs millisecondes.

Une raison supplémentaire de le faire sur le serveur est que certains navigateur Javascript horodatages sont inexactes: http://ejohn.org/blog/accuracy-of-javascript-time/ . Je soupçonne Node.js horodatages tout aussi précis (ou plus) que V8 (qui est l'un des rares précis).

Autres conseils

Vue d'ensemble:

Après socket.io connexion a été établie, vous créez un nouvel objet Date sur le client, Appelons-le startTime. Ceci est votre temps initial avant de faire une demande au serveur. Vous émettez alors un événement ping du client. convention de nommage est totalement à vous. serveur Pendant ce temps doit être à l'écoute pour un événement ping, et quand il reçoit le ping, il émet immédiatement un événement pong. Client attire alors l'événement pong. À ce moment, vous voulez créer un autre objet de la date qui représente Date.now(). Donc, à ce stade, vous avez deux objets de date - date initiale avant de faire une demande au serveur, et un autre objet de la date après avoir fait une demande au serveur et il répondu. Soustraire le startTime de temps en cours 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 Github Gist .

Qu'est-ce que je fais d'habitude d'envoyer horodatage à la demande:

  1. Sur le client, créez un new Date() et envoyer timestamp: date.getTime() au serveur, à chaque requête JSON.
  2. Sur le serveur, à la réception d'une demande, mettre un processed: (new Date()).getTime() dans l'objet.
  3. demande de la poignée.
  4. Sur la réponse, a mis le timestamp de la demande, et un nouveau champ traité: processed: (new Date()).getTime() - req.processed qui contient maintenant le nombre de millisecondes qu'il a fallu pour traiter la demande
  5. .
  6. Sur le client, lors de la réception d'une réponse, prenez la timestamp (qui est la même qui a été envoyé sur pt 1) et soustraire de l'heure actuelle, et soustraire le temps de traitement (de processed), et il est votre « vrai » temps de ping en millisecondes.

Je pense que vous devriez toujours inclure le temps pour les deux demande et la réponse dans le temps de ping, même s'il existe une communication à sens unique. En effet, c'est le sens derrière la norme « temps de ping » et « temps d'attente ». Et si elle est une communication à sens unique et le temps de latence est seulement la moitié du temps réel ping, qui est juste une « bonne chose ».

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

... Je n'était toujours pas satisfaite. J'ai visité les documents officiels et bien, bien, bien -. La solution est déjà intégrée

Vous avez juste besoin de mettre en œuvre - départ le 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});

Heres mon très rapide et un script sale pour tester le ping ... juste la tête http: // yourserver: 8080 dans votre navigateur et de regarder 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 sont assez élevés (200-400ms aller-retour) sur de grandes boîtes PVs w / ressources dédiées à la fois en Californie et au New Jersey. (Je suis sur la côte est) Je parie Theres juste beaucoup de temps d'attente sur les boîtes vps b / c ils sont au service tellement de trafic?

La seule chose qui me fait est qu'un ping régulier du terminal Linux du même client au même serveur est 11ms sur le facteur d'une moyenne de 10 bas ... Je suis en train de faire quelque chose de mal ou est quelque chose de lent avec Node.js /socket.io/websockets?

Lire d 'abord -. En raison de questions répétées pourquoi il est censé travailler, permettez-moi de clarifier un peu

  • La fonction de rappel client est exécuté sur le client, qui est la raison pour laquelle il a accès à la fermeture, y compris la variable start contenant l'horodatage. Ceci 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 un funtion de rappel, qui semble être exécuté par le serveur, mais cela fait passe juste les arguments de la fonction via la prise Web et le client appelle ensuite la fonction de rappel.

Qu'est-ce qui se passe ci-dessous (s'il vous plaît faire vérifier le code exemple!):

  1. client stocke l'horodatage en cours 1453213686429 dans start
  2. Le client envoie un événement ping au serveur et attend une réponse
  3. Server répond à l'événement ping avec « S'il vous plaît appelez 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 de démonstration si vous voulez voir des arguments)
  5. clientCallback reprend l'horodatage en cours sur le client , par exemple 1453213686449, et sait que 20 ms se sont écoulés depuis qu'il a envoyé la demande.

Imaginez le Druid (client) tenant un chronomètre et appuyez sur le bouton quand le messager (événement) se met à courir, et en le poussant à nouveau quand le messager arrive avec son rouleau (arguments de la fonction) . Le druide lit alors le livre et ajoute les noms d'ingrédients à sa recette de potion et brasse la potion. (rappel)

Ok, oubliez le paragraphe précédent, je suppose que vous avez obtenu le point.


Bien que la question a déjà répondu, voici une courte mise en œuvre pour le contrôle de la 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émonstration

Code Demo comme module de noeud: socketIO-callback.tgz configurer et exécuter avec

npm install
node callback.js

et puis accédez à http: // localhost: 5060

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top