我正在尝试使用 NodeJS 创建多人游戏,并且我想在客户端之间同步操作。
找到客户端和服务器之间的延迟(请求返回客户端所需的时间)的最佳方法是什么?
我的第一个想法是客户端 #1 可以发送带有请求的时间戳,因此当客户端 #2 将接收客户端 #1 的操作时,他将调整操作速度以消除请求的延迟。但问题是两个客户端的系统日期时间可能不相同,因此两个客户端不可能知道客户端 #1 请求的卷轴延迟。
另一个解决方案是使用服务器的时间戳,但现在我怎么知道客户端的延迟?
……我还是不满意。我访问了官方文档,嗯,嗯,嗯 - 解决方案已经内置。
你只需要实现它 - 看看我的:
// (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});
我将假设您正在使用 WebSockets 或Socket.IO,因为您正在实施延迟很重要的游戏(并且您将其标记为这样)。
我认为服务器可能应该为每个客户端测量并跟踪这一点。
您可能希望实现服务器可以请求客户端的某种 ping 操作。一旦客户端收到请求,它就会向服务器发送回响应。然后服务器除以 2 并更新该客户端的延迟。您可能希望服务器定期对每个客户端执行此操作,并可能平均最后几个,这样您就不会因突然但暂时的峰值而出现奇怪的行为。
然后,当有来自一个客户端的消息需要发送(或广播)到另一个客户端时,服务器可以将 client1 的延迟添加到 client2 的延迟,并将其作为延迟偏移作为消息的一部分传递给 client2。然后,client2 将知道 client1 上的事件发生在几毫秒前。
在服务器上执行此操作的另一个原因是某些浏览器 Javascript 时间戳不准确:http ://ejohn.org/blog/accuracy-of-javascript-time/ 。我怀疑 node.js 时间戳与 V8 一样准确(或更准确)(这是为数不多的准确时间戳之一)。
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使用。
我通常会用请求发送时间戳:
new Date()
并将每个 JSON 请求发送timestamp: date.getTime()
到服务器。processed: (new Date()).getTime()
放入对象中。timestamp
来自请求的 和一个新的已处理字段:processed: (new Date()).getTime() - req.processed
现在包含处理请求所用的毫秒数。timestamp
(与在 pt 1 上发送的相同)并从当前时间中减去它,然后减去处理时间processed
(我认为您应该始终在 ping 时间中包含请求和响应的时间,即使是单向通信也是如此。这是因为这是“ping time”和“latency”背后的标准含义。而如果是单向通信,延迟只有真实ping时间的一半,那简直是“好事”。
这是我测试 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?