如何在带有套接字(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使用 。

我通常做什么来发送时间戳与请求:

  1. 在客户端上,创build一个new Date() ,并将每个JSON请求的timestamp: date.getTime()发送到服务器。
  2. 在服务器上,当收到请求时,在对象中放入一个processed: (new Date()).getTime()
  3. 处理请求。
  4. 在响应中,将请求的timestamp和新的处理后的字段: processed: (new Date()).getTime() - req.processed现在包含处理请求所用的毫秒数。
  5. 在客户端,当收到一个响应时,采取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函数在客户端执行,这就是为什么它可以访问闭包,包括包含时间戳的startvariables。
  • 服务器自然不能调用客户端上的任意函数并访问函数的闭包。 但是socket.io允许定义一个callback函数,这似乎是由服务器执行的,但实际上只是通过web套接字传递函数参数,然后客户端调用callback函数。

下面会发生什么(请检查示例代码!):

  1. 客户端在start存储当前时间戳1453213686429
  2. 客户端发送一个ping事件到服务器,并正在等待答案
  3. 服务器响应ping事件“请用空参数调用您的callback”
  4. 客户端收到响应并用空参数调用clientCallback (如果想查看参数,请查看演示代码)
  5. 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});