Como posso encontrar o tempo de resposta (latência) de um cliente no NodeJS com soquetes (soquete.io)?

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

Pergunta

Estou tentando criar um jogo multiplayer com o NodeJS e quero sincronizar a ação entre os clientes.

Qual seria a melhor maneira de encontrar a latência (o tempo que uma solicitação leva para voltar ao cliente) entre o cliente e o servidor?

Minha primeira idéia foi que o cliente nº 1 pudesse enviar um registro de data e hora, portanto, quando o cliente #2 receber a ação do cliente nº 1 que ele ajustará é a velocidade de ação para remover o atraso da solicitação. Mas o problema é que talvez o tempo de data do sistema dos dois clientes não seja idêntico, portanto, não é possível que dois saibam o atraso do rolo na solicitação do cliente nº 1.

A outra solução foi usar o registro de data e hora do servidor, mas agora como posso saber a latência de um cliente?

Foi útil?

Solução

Vou assumir que você está usando websockets ou Socket.io Como você está implementando um jogo em que a latência é importante (e você o marcou como tal).

Eu acho que o servidor provavelmente deveria medir e acompanhar isso para cada cliente.

Você provavelmente deseja implementar algum tipo de ação de ping que o servidor possa solicitar do cliente. Assim que o cliente receber a solicitação, ele envia de volta uma resposta ao servidor. O servidor divide por 2 e atualiza a latência desse cliente. Você provavelmente deseja que o servidor faça isso periodicamente com cada cliente e provavelmente tenha uma média nos últimos vários, para que você não obtenha um comportamento estranho de picos repentinos, mas temporários.

Então, quando há uma mensagem de um cliente que precisa ser enviado (ou transmitido) para outro cliente, o servidor pode adicionar a latência do Cliente1 à latência do Client2 e comunicar isso como o deslocamento da latência ao Client2 como parte da mensagem. O Client2 saberá então que o evento no Client1 aconteceu que muitos milissegundos atrás.

Um motivo adicional para fazer isso no servidor é que alguns registros de data e hora do JavaScript do navegador são imprecisos: http://ejohn.org/blog/accuracy-of-javascript time/. Suspeito que os timestamps Node.js sejam igualmente precisos (ou mais) que o V8 (que é um dos poucos precisos).

Outras dicas

Visão geral:

Depois que a conexão Socket.io foi estabelecida, você cria um novo Date objeto no cliente, vamos chamá -lo startTime. Isto é seu hora inicial antes de fazer uma solicitação ao servidor. Você então emite um ping evento do cliente. A Convenção de Nomeação depende totalmente de você. Enquanto isso, o servidor deve estar ouvindo para um ping evento, e quando recebe o ping, emite imediatamente um pong evento. Cliente então pega o pong evento. Neste momento, você deseja criar outro objeto de data que represente Date.now(). Portanto, neste ponto, você tem dois objetos de data - data inicial antes de fazer uma solicitação ao servidor e outro objeto de data depois de fazer uma solicitação ao servidor e ele respondeu. Subtrair o startTime do tempo atual e você tem o 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');
  });
});

Também disponível como um Github Gist.

O que costumo fazer para enviar o registro de data e hora com a solicitação:

  1. No cliente, crie um new Date() e envia timestamp: date.getTime() para o servidor, a cada solicitação JSON.
  2. No servidor, ao receber uma solicitação, coloque um processed: (new Date()).getTime() no objeto.
  3. Lidar com a solicitação.
  4. Na resposta, coloque o timestamp A partir da solicitação e um novo campo processado: processed: (new Date()).getTime() - req.processed Isso agora contém o número de milissegundos necessários para processar a solicitação.
  5. No cliente, ao receber uma resposta, pegue o timestamp (que é o mesmo que foi enviado no Pt 1) e subtrai -lo do horário atual e subtrair o tempo de processamento (processed), e existe o seu tempo de ping "real" em milissegundos.

Eu acho que você deve sempre incluir o tempo para solicitação e resposta no tempo do ping, mesmo que haja comunicação unidirecional. Isso ocorre porque esse é o significado padrão por trás do "tempo de ping" e "latência". E se for uma comunicação unidirecional e a latência é apenas metade do tempo real do ping, isso é apenas uma "coisa boa".

Depois de ler todas essas respostas ...

... Eu ainda não estava satisfeito. Eu visitei os documentos oficiais e bem, bem, bem - a solução já está interna.

Você só precisa implementá -lo - confira o meu:

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

Aqui está meu script muito rápido e sujo para testar o ping ... apenas vá para http: // seuerver: 8080 no seu navegador e assista ao console (terminal ssh para mim).

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

Estou muito curioso sobre isso, porque parece que meus pings são bem altos (ida e volta de 200 a 400ms) em grandes caixas VPS com recursos dedicados, tanto na Califórnia quanto em Nova Jersey. (Estou na costa leste) Estou apostando que há muita latência nas caixas VPS porque eles estão servindo tanto tráfego?

O que me pega é que um ping regular do terminal Linux do mesmo cliente para o mesmo servidor é de 11ms, em média, um fator de 10 mais baixo ... Estou fazendo algo errado ou é algo lento com o node.js/soquete. io/websockets?

Leia primeiro - Devido a perguntas repetidas por que isso deve funcionar, deixe -me esclarecer um pouco.

  • A função de retorno de chamada do cliente é executado no cliente, é por isso que tem acesso ao fechamento, incluindo o start variável que contém o carimbo de hora. Isto é O argumento ack () em soquete.io.
  • O servidor naturalmente não pode chamar uma função arbitrária no cliente e acessar o fechamento da função. Mas socket.io permite definir uma função de retorno de chamada, que parece ser executado No servidor, mas isso realmente passa os argumentos da função através do soquete da web, e o cliente chama o retorno de chamada.

O que acontece abaixo (por favor, verifique o código de exemplo!):

  1. CLIE 1453213686429 dentro start
  2. O cliente envia um ping evento para o servidor e está aguardando uma resposta
  3. O servidor responde ao evento de ping com “Ligue para o seu retorno de chamada com argumentos vazios”
  4. O cliente recebe a resposta e liga clientCallback com argumentos vazios (verifique o código da demonstração se quiser ver argumentos)
  5. clientCallback novamente leva o carimbo de data / hora atual no cliente, por exemplo 1453213686449, e sabe disso 20 ms já passaram desde que enviou a solicitação.

Imagine o druida (cliente) segurando um cronômetro e empurrando o botão quando o mensageiro (evento) começa a correr e empurrando -o novamente quando o mensageiro chega com seu rolagem (Argumentos da função). O druida então lê o pergaminho e adiciona os nomes de ingredientes à sua receita de poção e fabrica a poção. (ligue de volta)

Ok, esqueça o parágrafo anterior, acho que você entendeu.


Embora a pergunta já tenha sido respondida, aqui uma breve implementação para verificar a RTT com 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
} );

Código de demonstração

Código de demonstração como módulo de nó: Socketio-Callback.tgz Configure -o e execute -o com

npm install
node callback.js

e então navegue para http: // localhost: 5060

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top