¿Cómo puedo encontrar el tiempo de respuesta (latencia) de un cliente en NodeJS con tomas (socket.io)?

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

Pregunta

Estoy intentando crear un juego multijugador con NodeJS y quiero sincronizar la acción entre los clientes.

¿Cuál sería la mejor manera de encontrar la latencia (el tiempo que toma una solicitud para volver al cliente) entre el cliente y el servidor?

Mi primera idea era que el cliente # 1 podría enviar una marca de tiempo con el es petición, por lo que cuando el cliente # 2 recibirá la acción del cliente # 1 se ajustará es la velocidad de acción para eliminar el retraso de la solicitud. Pero el problema es que tal vez la fecha y hora del sistema de los dos clientes no son idénticos por lo que no es posible saber el retraso de dos carretes en la petición de cliente # 1.

La otra solución era utilizar la marca de tiempo del servidor, pero ahora ¿cómo puedo saber el estado latente de un cliente?

¿Fue útil?

Solución

Me voy a asumir que usted está utilizando WebSockets o Socket.IO ya que están poniendo en práctica un juego donde la latencia asuntos (y más te han etiquetado como tal).

Yo pensaría el servidor probablemente debe medir y hacer un seguimiento de esto para cada cliente.

Probablemente desee poner en práctica algún tipo de acción de ping que el servidor puede solicitar del cliente. Tan pronto como el cliente recibe la solicitud, envía de vuelta una respuesta al servidor. El servidor entonces se divide por 2 y actualiza la latencia para ese cliente. Es probable que el servidor para hacer esto periódicamente con cada cliente y probablemente la media de los últimos de manera que no obtiene un comportamiento extraño de los picos repentinos, pero temporales.

Entonces, cuando hay un mensaje de un cliente que tiene que ser enviado (o difusión) a otro cliente, el servidor puede añadir latencia de cliente1 a la latencia de client2 y comunicar esto como la latencia de compensación a client2 como parte del mensaje. client2 sabrá entonces que el evento ocurrió en cliente1 hace que muchos milisegundos.

Una razón adicional para hacer esto en el servidor es que algunas marcas de tiempo del navegador Javascript son inexactas: http://ejohn.org/blog/accuracy-of-javascript-time/ . Me Node.js sospechosas marcas de tiempo son tan precisas (o más) que V8 (que es uno de los pocos precisos).

Otros consejos

Descripción:

Una vez establecida la conexión socket.io, se crea un nuevo objeto Date en el cliente, vamos a llamarlo startTime. Esta es su tiempo inicial antes de hacer una solicitud al servidor. A continuación, emitirá un evento ping desde el cliente. Convención de nomenclatura es totalmente de usted. Mientras tanto, el servidor debe estar escuchando para un evento ping, y cuando recibe la ping, inmediatamente se emite un evento pong. Cliente entonces atrapa el evento pong. En este momento desea crear otro objeto fecha que representa Date.now(). Así que en este momento tiene dos objetos de fecha - fecha inicial antes de hacer una solicitud al servidor, y otro objeto de fecha después de realizar una petición al servidor y se respondió. Restar el startTime desde el momento actual y usted tiene la latency.

Cliente

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);
});

Servidor

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

También disponible como Github Gist .

Lo que suelo hacer para enviar marca de tiempo con la solicitud:

  1. En el cliente, crear un new Date() y timestamp: date.getTime() enviar al servidor, con cada solicitud JSON.
  2. En el servidor, al recibir una solicitud, poner un processed: (new Date()).getTime() en el objeto.
  3. Solicitud de Mango.
  4. En la respuesta, puso el timestamp partir de la solicitud, y un nuevo campo procesado: processed: (new Date()).getTime() - req.processed que ahora contiene el número de milisegundos que se tardó en procesar la solicitud
  5. .
  6. En el cliente, al recibir una respuesta, tomar la timestamp (que es el mismo que fue enviado en pt 1) y restarlo de la hora actual, y restar el tiempo de procesamiento (processed), y no es su "real" tiempo de ping en milisegundos.

creo que siempre debe incluir el tiempo para ambos petición y la respuesta en el tiempo de ping, incluso si no hay comunicación unidireccional. Esto se debe a que es el significado estándar detrás de "tiempo de ping" y "latencia". Y si se trata de una comunicación unidireccional y la latencia es sólo la mitad del tiempo real de ping, que es sólo un "bueno".

Después de leer todas estas respuestas ...

... todavía no estaba satisfecho. Visité los documentos oficiales y bueno, bueno, bueno -. La solución ya está incorporado

Sólo tiene que implementarlo - check out mío:

Cliente

// (Connect to socket).

var latency = 0;

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

    console.log(latency);
});

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

Servidor

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});

Aquí está mi muy rápido y la escritura sucia para probar el ping ... sólo la cabeza a http: // yourserver: 8080 en su navegador y ver la consola (terminal SSH para mí).

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(){});
});

Estoy muy curioso acerca de esto porque parece como si mis pings son bastante altos (200-400ms ida y vuelta) en grandes cajas de VPS w / recursos dedicados tanto en California y Nueva Jersey. (Estoy en la costa este) Estoy apostando theres sólo un montón de latencia en las cajas de VPS b / c que están sirviendo tanto tráfico?

Lo que me pone es que un ping regular desde el terminal de Linux desde el mismo cliente en el mismo servidor es 11 ms en un factor de menor promedio de 10 ... estoy haciendo algo mal o es algo lento con Node.js /socket.io/websockets?

Leer primero -. Debido a las repetidas preguntas de por qué esto se supone que funciona, quiero aclarar un poco

  • La función de devolución de llamada del cliente es ejecutada en el cliente, que es por eso que tiene acceso a la clausura, incluyendo la variable start que contiene la marca de tiempo. Este es el ack () argumento en socket.io.
  • El servidor de forma natural no puede llamar a una función arbitraria en el cliente y acceder cierre de la función. Pero socket.io permite definir una funcion de devolución de llamada, que parece ser ejecutado por el servidor, pero esto en realidad sólo pasa los argumentos de la función a través de la toma de red, y el cliente luego llama a la devolución de llamada.

Lo que sucede a continuación (Por favor, compruebe el código de ejemplo!):

  1. Client almacena fecha y hora actual en 1453213686429 start
  2. El cliente envía un evento ping al servidor y está esperando una respuesta
  3. servidor responde al evento de ping con “Por favor, llame a su respuesta con argumentos vacíos”
  4. El cliente recibe la respuesta y las llamadas clientCallback con argumentos vacíos (Marque el código de demostración si quieres ver argumentos)
  5. clientCallback toma de nuevo la fecha y hora actual en el cliente , por ejemplo, 1453213686449, y sabe que 20 ms han pasado desde que se envió la solicitud.

Imagine el druida (cliente) de un cronómetro y empujando el botón cuando el mensajero (evento) empieza a correr, y empujando de nuevo cuando el mensajero llega con su rollo (argumentos de la función) . El druida continuación, lee el libro y añade los nombres de los ingredientes de su receta de poción y elabora la poción. (devolución de llamada)

Está bien, olvidar el párrafo anterior, supongo que tienes el punto.


A pesar de que la pregunta ya ha sido contestada, aquí una breve aplicación para el control de la RTT con socket.io:

Cliente

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

Servidor

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

Demostración Código

código de demostración como módulo de nodo: socketIO-callback.tgz instalarlo y ejecutarlo con

npm install
node callback.js

y vaya a http: // localhost: 5060

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top