29

我正在尝试使用 NodeJS 创建多人游戏,并且我想在客户端之间同步操作。

找到客户端和服务器之间的延迟(请求返回客户端所需的时间)的最佳方法是什么?

我的第一个想法是客户端 #1 可以发送带有请求的时间戳,因此当客户端 #2 将接收客户端 #1 的操作时,他将调整操作速度以消除请求的延迟。但问题是两个客户端的系统日期时间可能不相同,因此两个客户端不可能知道客户端 #1 请求的卷轴延迟。

另一个解决方案是使用服务器的时间戳,但现在我怎么知道客户端的延迟?

4

6 回答 6

30

在阅读了所有这些答案后...

……我还是不满意。我访问了官方文档,嗯,嗯,嗯 - 解决方案已经内置。

你只需要实现它 - 看看我的:

客户

// (Connect to socket).

var latency = 0;

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

    console.log(latency);
});

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

 服务器

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});
于 2017-07-20T13:43:40.433 回答
27

我将假设您正在使用 WebSockets 或Socket.IO,因为您正在实施延迟很重要的游戏(并且您将其标记为这样)。

我认为服务器可能应该为每个客户端测量并跟踪这一点。

您可能希望实现服务器可以请求客户端的某种 ping 操作。一旦客户端收到请求,它就会向服务器发送回响应。然后服务器除以 2 并更新该客户端的延迟。您可能希望服务器定期对每个客户端执行此操作,并可能平均最后几个,这样您就不会因突然但暂时的峰值而出现奇怪的行为。

然后,当有来自一个客户端的消息需要发送(或广播)到另一个客户端时,服务器可以将 client1 的延迟添加到 client2 的延迟,并将其作为延迟偏移作为消息的一部分传递给 client2。然后,client2 将知道 client1 上的事件发生在几毫秒前。

在服务器上执行此操作的另一个原因是某些浏览器 Javascript 时间戳不准确:http ://ejohn.org/blog/accuracy-of-javascript-time/ 。我怀疑 node.js 时间戳与 V8 一样准确(或更准确)(这是为数不多的准确时间戳之一)。

于 2010-11-01T19:07:14.130 回答
24

概述:

socket.io 连接建立后,Date在客户端创建一个新对象,我们称之为startTime。这是您向服务器发出请求之前的初始时间。然后,您从客户端发出一个ping事件。命名约定完全取决于您。同时服务器应该正在监听一个ping事件,当它收到时ping,它会立即发出一个pong事件。客户端然后捕获pong事件。此时您要创建另一个表示Date.now(). 因此,此时您有两个日期对象 - 向服务器发出请求之前的初始日期,以及在您向服务器发出请求并回复之后的另一个日期对象。startTime从当前时间减去latency.

客户

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

服务器

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

也可作为Github Gist使用。

于 2014-01-10T23:45:29.493 回答
6

我通常会用请求发送时间戳:

  1. 在客户端上,创建一个new Date()并将每个 JSON 请求发送timestamp: date.getTime()到服务器。
  2. 在服务器上,收到请求后,将 aprocessed: (new Date()).getTime()放入对象中。
  3. 处理请求。
  4. 在响应中,放置timestamp来自请求的 和一个新的已处理字段:processed: (new Date()).getTime() - req.processed现在包含处理请求所用的毫秒数。
  5. 在客户端上,当接收到响应时,取timestamp(与在 pt 1 上发送的相同)并从当前时间中减去它,然后减去处理时间processed

我认为您应该始终在 ping 时间中包含请求和响应的时间,即使是单向通信也是如此。这是因为这是“ping time”和“latency”背后的标准含义。而如果是单向通信,延迟只有真实ping时间的一半,那简直是“好事”。

于 2010-11-03T11:58:39.373 回答
1

这是我测试 ping 的快速而肮脏的脚本……只需在浏览器中访问http://yourserver:8080并观看控制台(我的 ssh 终端)。

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

我对此非常好奇,因为在加利福尼亚州和新泽西州的带有专用资源的大型 vps 盒子上,我的 ping 似乎相当高(往返 200-400 毫秒)。(我在东海岸)我敢打赌 vps 盒子 b/c 上只有很多延迟,他们服务这么多流量?

让我感到惊讶的是,从同一客户端到同一服务器的 linux 终端的常规 ping 平均为 11 毫秒,降低了 10 倍……我做错了什么还是 node.js/socket 速度慢。 io/websockets?

于 2010-11-03T12:41:54.323 回答
0
于 2014-03-14T13:05:18.463 回答