Come posso trovare il tempo di risposta (latenza) di un client in NodeJS con socket (socket.io)?

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

Domanda

Sto provando a creare un gioco multiplayer con NodeJS e voglio sincronizzare l'azione tra i client.

Quale sarebbe il modo migliore per trovare la latenza (il tempo impiegato da una richiesta per tornare al client) tra il client e il server?

La mia prima idea era che il client n. 1 potesse inviare un timestamp con la richiesta, quindi quando il client n. 2 riceverà l'azione del client n. 1 regolerà la velocità dell'azione per rimuovere il ritardo della richiesta.Ma il problema è che forse la data e l'ora del sistema dei due client non sono identiche, quindi non è possibile che due conoscano il ritardo della bobina su richiesta del client n. 1.

L'altra soluzione era utilizzare il timestamp del server, ma ora come posso conoscere la latenza di un client?

È stato utile?

Soluzione

ho intenzione di assumere che si sta utilizzando WebSockets o Socket.IO dal momento che stanno attuando un gioco in cui latenza questioni (e ti hanno taggato come tale).

I penserebbe il server dovrebbe probabilmente misurare e tenere traccia di questo per ogni cliente.

Probabilmente si vuole attuare una sorta di azione di ping che il server può richiedere del cliente. Non appena il cliente riceve la richiesta, invia una risposta al server. Il server quindi divide per 2 e aggiorna la latenza per quel cliente. Probabilmente si desidera che il server per fare questo periodicamente con ogni cliente e, probabilmente, la media degli ultimi in modo che non si ottiene un comportamento strano da improvvisi ma temporanei picchi.

Poi, quando c'è un messaggio da un cliente che ha bisogno di essere inviati (o trasmissione) a un altro client, il server può aggiungere la latenza di client1 alla latenza di client2 e comunicare questo come l'offset Client2 come parte del messaggio di latenza. Client2 sarà poi sapere che l'evento su CLIENT1 è accaduto che molti millisecondi fa.

Un motivo in più per fare questo sul server è che alcuni browser che supporti JavaScript timestamp sono inesatte: http://ejohn.org/blog/accuracy-of-javascript-time/ . I sospetti Node.JS timestamp sono altrettanto precise (o più) di V8 (che è uno dei pochi quelli accurati).

Altri suggerimenti

Panoramica:

Dopo socket.io connessione è stata stabilita, si crea un nuovo oggetto Date sul client, chiamiamolo startTime. Questo è il tuo tempo iniziale prima di fare una richiesta al server. È quindi emettere un evento ping dal client. Convenzione di denominazione è totalmente a voi. Server Nel frattempo dovrebbe essere in ascolto per un evento ping, e quando riceve il ping, emette subito un evento pong. Cliente poi cattura l'evento pong. In questo momento si desidera creare un altro oggetto Data che rappresenta Date.now(). Quindi a questo punto hai due oggetti Date - data iniziale prima di fare una richiesta al server, e un altro oggetto data dopo aver effettuato una richiesta al server ed è risposto. Sottrarre il startTime da ora corrente e si ha la 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);
});

Server

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

Disponibile anche come Github Gist .

Cosa faccio di solito per inviare il timestamp con la richiesta:

  1. Sul client, creare un file new Date() e invia timestamp: date.getTime() al server, con ogni richiesta JSON.
  2. Sul server, dopo aver ricevuto una richiesta, inserire a processed: (new Date()).getTime() nell'oggetto.
  3. Gestire la richiesta.
  4. Nella risposta, metti il timestamp dalla richiesta e un nuovo campo elaborato: processed: (new Date()).getTime() - req.processed che ora contiene il numero di millisecondi necessari per elaborare la richiesta.
  5. Sul client, quando ricevi una risposta, prendi il file timestamp (che è lo stesso inviato al punto 1) e sottrailo dall'ora corrente e sottrai il tempo di elaborazione (processed) e c'è il tempo di ping "reale" in millisecondi.

Penso che dovresti sempre includere il tempo sia per la richiesta che per la risposta nel tempo del ping, anche se c'è una comunicazione unidirezionale.Questo perché questo è il significato standard dietro "ping time" e "latenza".E se la comunicazione è unidirezionale e la latenza è solo la metà del tempo di ping reale, è semplicemente una "buona cosa".

Dopo aver letto tutte queste risposte ...

... io ancora non era soddisfatto. Ho visitato la documentazione ufficiale e bene, bene, bene -. La soluzione è già built-in

Hai solo bisogno di attuarlo - check out la mia:

Client

// (Connect to socket).

var latency = 0;

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

    console.log(latency);
});

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

Server

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

Ecco il mio veramente veloce e lo script sporco per testare il ping ... solo capo a http: // yourserver: 8080 nel tuo browser e guardare la console (terminale SSH per me).

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

Sono molto curioso di questo perché sembra che i miei i ping sono piuttosto alti (200-400ms andata e ritorno) in grandi scatole VPS risorse dedicate w / sia in California e New Jersey. (Io sono sulla costa orientale) Sto Theres solo un sacco di latenza di scommettere sulle VPS scatole b / c che stanno servendo così tanto traffico?

La cosa che mi colpisce è che un ping regolare dal terminale linux dallo stesso client allo stesso server è 11ms su un fattore medio di 10 inferiore ... Sto facendo qualcosa di sbagliato o è qualcosa di lento con node.js /socket.io/websockets?

Leggi prima - A causa delle ripetute domande sul perché dovrebbe funzionare, vorrei chiarire un po'.

  • La funzione di callback del client è eseguito sul cliente, ecco perché ha accesso alla chiusura, compreso il start variabile contenente il timestamp.Questo è l'argomento ack() in socket.io.
  • Il server naturalmente non può chiamare una funzione arbitraria sul client e accedere alla chiusura della funzione.Ma socket.io permette di definire una funzione di callback, che sembra essere eseguito dal server, ma in realtà questo passa semplicemente gli argomenti della funzione attraverso il socket web e il client quindi chiama il callback.

Cosa succede di seguito (controlla il codice di esempio!):

  1. Il client memorizza il timestamp corrente 1453213686429 In start
  2. Il cliente invia un ping evento al server ed è in attesa di una risposta
  3. Il server risponde all'evento ping con "Chiama la richiamata con argomenti vuoti"
  4. Il cliente riceve la risposta e chiama clientCallback con argomenti vuoti (controlla il codice demo se vuoi vedere gli argomenti)
  5. clientCallback prende nuovamente il timestamp corrente sul cliente, per esempio. 1453213686449, e lo sa 20 ms sono trascorsi da quando ha inviato la richiesta.

Immagina il druido (cliente) tenendo un cronometro e premendo il pulsante quando il messenger (evento) comincia a correre, e lo spinge di nuovo quando arriva il messaggero con la sua pergamena (argomenti della funzione).Il druido poi legge la pergamena e aggiunge i nomi degli ingredienti alla ricetta della sua pozione e prepara la pozione. (richiamare)

Ok, dimentica il paragrafo precedente, immagino che tu abbia capito il punto.


Sebbene alla domanda sia già stata data una risposta, ecco una breve implementazione per verificare l'RTT socket.io:

Cliente

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

server

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

Codice dimostrativo

Codice demo come modulo nodo: socketIO-callback.tgz Configuralo ed eseguilo con

npm install
node callback.js

e poi vai a http://localhost:5060

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top