如何在带有套接字(socket.io)的NodeJS中查找客户端的响应时间(延迟)?
我试图用NodeJS创build一个多人游戏,我想同步客户端之间的动作。
在客户端和服务器之间find延迟(请求返回到客户端的时间)的最佳方法是什么?
我的第一个想法是客户端#1可以发送一个时间戳与请求,所以当客户端#2将收到客户端#1的行动,他将调整是行动的速度,以消除请求的延迟。 但是问题是两个客户端的系统date时间可能不相同,所以根据客户端#1的请求不可能知道卷轴延迟。
另一种解决scheme是使用服务器的时间戳,但现在我怎么知道客户端的延迟?
我假定你正在使用WebSockets或者Socket.IO,因为你正在实现一个延迟很重要的游戏(你把它标记为这样)。
我认为服务器应该可能测量和跟踪每个客户端的这一点。
你可能想要实现服务器可以请求客户端的某种ping动作。 一旦客户端收到请求,就会向服务器发回一个响应。 然后服务器除以2,并更新该客户端的延迟。 您可能希望服务器定期对每个客户端执行此操作,并且可能平均过去的几个,以避免突然出现暂时高峰时出现的exception行为。
然后,当有一个客户端需要发送(或广播)到另一个客户端的消息时,服务器可以将客户端1的延迟添加到客户端2的延迟时间,并作为消息的一部分作为延迟偏移量传递给客户端2。 然后客户端2会知道客户端1上的事件发生在几毫秒前。
在服务器上执行此操作的另一个原因是某些浏览器JavaScript时间戳不准确: http : //ejohn.org/blog/accuracy-of-javascript-time/ 。 我怀疑node.js时间戳与V8(这是less数几个精确的时间戳之一)一样准确(或者更加如此)。
概述:
在build立socket.io连接之后,在客户端上创build一个新的Date
对象,我们称之为startTime
。 这是您向服务器发出请求之前的最初时间 。 然后您从客户端发出一个ping
事件。 命名约定完全取决于你。 同时服务器应该正在侦听一个ping
事件,当它接收到ping
,它立即发出一个pong
事件。 然后客户抓住pong
事件。 这时你想创build另一个代表Date.now()
date对象。 所以在这一点上,你有两个date对象 – 在向服务器发出请求之前的最初date,以及在向服务器发出请求并回复之后的另一个date对象。 从当前时间减去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使用 。
我通常做什么来发送时间戳与请求:
- 在客户端上,创build一个
new Date()
,并将每个JSON请求的timestamp: date.getTime()
发送到服务器。 - 在服务器上,当收到请求时,在对象中放入一个
processed: (new Date()).getTime()
。 - 处理请求。
- 在响应中,将请求的
timestamp
和新的处理后的字段:processed: (new Date()).getTime() - req.processed
现在包含处理请求所用的毫秒数。 - 在客户端,当收到一个响应时,采取
timestamp
(这是相同的发送1点),并从当前时间减去,减去处理时间(processed
),并有你的“真正的”平时间毫秒。
我认为即使有单向通信,也应该在ping时间内包含请求和响应的时间。 这是因为这是“ping time”和“latency”背后的标准含义。 而如果是单向通信,延迟只是实际通话时间的一半,那只是一件“好事”。
下面是我真正快速和肮脏的脚本来testing平…只要在浏览器中的http:// yourserver:8080 ,并观看控制台(SSHterminal为我)。
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箱子里都有专门的资源,看起来我的平均身高很高(200-400ms往返)。 (我在东海岸)我打赌他们正在服务这么多的stream量vps箱b / c很多延迟?
得到我的是一个普通的ping从linuxterminal从同一个客户端到同一台服务器是11毫秒,平均低10倍…我是做错了什么,或者是与node.js /套接字慢。 IO /的WebSockets?
先阅读 –由于重复的问题,为什么这应该工作,让我澄清一点。
- 客户端callback函数在客户端执行,这就是为什么它可以访问闭包,包括包含时间戳的
start
variables。 - 服务器自然不能调用客户端上的任意函数并访问函数的闭包。 但是
socket.io
允许定义一个callback函数,这似乎是由服务器执行的,但实际上只是通过web套接字传递函数参数,然后客户端调用callback函数。
下面会发生什么(请检查示例代码!):
- 客户端在
start
存储当前时间戳1453213686429
- 客户端发送一个
ping
事件到服务器,并正在等待答案 - 服务器响应ping事件“请用空参数调用您的callback”
- 客户端收到响应并用空参数调用
clientCallback
(如果想查看参数,请查看演示代码) -
clientCallback
再次获取客户端上的当前时间戳,例如1453213686449
,并知道发送请求后已经过了20 ms
。
想象一下,当信使(事件)开始运行时,德鲁伊(客户端)持有一个秒表,并按下button,当信使用滚动(函数参数)到达时再次按下button。 然后德鲁伊读取卷轴,并将配料名称添加到他的药水配方,并酿造魔药。 (回电话)
好吧,忘了上一段,我想你明白了。
虽然这个问题已经被回答了,但是在这里用socket.io
来检查RTT的一个简短的实现:
客户
var start = Date.now(); this.socket.emit( 'ping', function clientCallback() { console.log( 'Websocket RTT: ' + (Date.now() - start) + ' ms' ); } );
服务器
socket.on( 'ping', function ( fn ) { fn(); // Simply execute the callback on the client } );
演示代码
演示代码作为节点模块: socketIO-callback.tgz设置并运行它
npm install node callback.js
然后导航到http:// localhost:5060
阅读所有这些答案后
…我还是不满意。 我访问了官方文档,很好,这个解决scheme已经内置了。
你只需要实现它 – 检查我的:
客户
// (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});