如何在带有套接字的NodeJS中找到客户端的响应时间(延迟)(socket.io)?
题
我试图用NodeJS创建一个多人游戏,我想在客户端之间同步动作。
找到客户端和服务器之间的延迟(请求返回客户端所需的时间)的最佳方法是什么?
我的第一个想法是,客户端#1可以发送带有is请求的时间戳,因此当客户端#2将接收客户端#1的动作时,他将调整is动作速度以消除请求的延迟。但问题是,也许两个客户端的系统日期时间不相同,所以不可能知道客户端#1的请求上的卷轴延迟。
另一种解决方案是使用服务器的时间戳,但现在如何知道客户端的延迟?
解决方案
我要假设您正在使用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()
的日期对象。因此,此时您有两个日期对象-向服务器发出请求之前的初始日期,以及向服务器发出请求并回复后的另一个日期对象。减去当前时间的基因标记代码,您将获得基因标记代码。
客户
通用标签
服务器
通用标签
也可以作为 Github Gist 使用。
我通常做的发送时间戳与请求:
- 在客户,创建一个
new Date()
和送timestamp: date.getTime()
到服务器,与每一个JSON请求。 - 在服务器上,在接收请求时,把一个
processed: (new Date()).getTime()
在对象。 - 处理请求。
- 在响应,放
timestamp
从请求,以及一个新处理的领域:processed: (new Date()).getTime() - req.processed
现在包含的数量毫秒它采取处理请求。 - 在客户中,当收到响应,采取
timestamp
(这是相同的,被送上pt1),并减去它从目前的时间,并减去处理时间(processed
),还有就是你的"真正的"平时间在毫秒。
我认为你应该永远包括时间为请求和响应在平时,即使有一种方式沟通。这是因为这是标准背后的意义的"平时间"和"延迟".如果它是一个向通信和等待时间只有一半的真正平时,那只是一个"好事"。
阅读所有这些答案之后...
...我仍然不满意。我访问了官方文档,很好,很好-解决方案已经内置。
您只需要实现它-查看我的:
客户 通用标签
服务器 通用标签
这里有我真正又快速又肮脏的脚本来测试ping ...只需前往 http:// yourserver:8080 在浏览器中,并查看控制台(对我来说是ssh终端)。 通用标签
对此我感到很好奇,因为在大型vps盒子上,我的ping值很高(往返200-400ms),带有加利福尼亚和新泽西州的专用资源。(我在东海岸)我敢打赌他们正在提供大量流量的vps机顶盒上只有很多延迟吗?
让我感到困惑的是,从同一个客户端到同一个服务器的linux终端进行的常规ping平均平均低11毫秒,这是我做错了还是使用node.js做得很慢/socket.io/websockets?
先阅读 — 由于重复的问题,为什么这是应该工作,让我澄清一下。
- 客户端回调函数为 在客户端上执行, 这就是为什么它可以访问关闭,包括
start
包含时间戳的变量。这是 中的ack()参数socket.io... - 服务器自然不能在客户端调用任意函数并访问函数的闭包。但是
socket.io
允许定义一个回调函数, 似乎正在执行 由服务器,但这实际上只是通过web套接字传递函数参数,然后客户端调用回调。
下面会发生什么(请检查示例代码!):
- 客户端存储当前时间戳
1453213686429
在start
- 客户端发送
ping
事件到服务器,正在等待答案 - 服务器以"请用空参数调用您的回调"响应ping事件
- 客户端接收响应并调用
clientCallback
使用空参数(如果您想查看参数,请检查演示代码) clientCallback
再次获取当前时间戳 在客户端上, ,例如1453213686449
, ,并且知道20 ms
已经通过,因为它发送的请求。
想象一下德鲁伊 (客户) 拿着秒表,当信使按下按钮 (活动) 开始运行,当信使带着他的卷轴到达时再次推动它 (函数参数).德鲁伊然后阅读卷轴并将成分名称添加到他的药水配方中并酿造药水。 (回调)
好吧,忘了前一段,我想你明白了。
虽然这个问题已经得到了回答,但这里有一个简短的实现,用于检查RTT socket.io
:
客户群
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-回调。tgz,tgz 设置它并运行它
npm install
node callback.js
然后导航到 http://localhost:5060