Come posso trovare il tempo di risposta (latenza) di un client in NodeJS con socket (socket.io)?
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?
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:
- Sul client, creare un file
new Date()
e inviatimestamp: date.getTime()
al server, con ogni richiesta JSON. - Sul server, dopo aver ricevuto una richiesta, inserire a
processed: (new Date()).getTime()
nell'oggetto. - Gestire la richiesta.
- 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. - 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!):
- Il client memorizza il timestamp corrente
1453213686429
Instart
- Il cliente invia un
ping
evento al server ed è in attesa di una risposta - Il server risponde all'evento ping con "Chiama la richiamata con argomenti vuoti"
- Il cliente riceve la risposta e chiama
clientCallback
con argomenti vuoti (controlla il codice demo se vuoi vedere gli argomenti) clientCallback
prende nuovamente il timestamp corrente sul cliente, per esempio.1453213686449
, e lo sa20 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