不一致的Date.now()值

我构build了一个HTML5多人游戏,取决于在服务器和客户端之间进行合理准确的时间同步。 在大多数情况下,我使用的algorithm是非常准确的 – 它只是估计客户端服务器时间增量是什么,即服务器当前时间与客户端当前时间之间的差异。 例如,如果服务器时间比客户端时间提前5秒,则时间增量为5000毫秒。

客户端和服务器(node.js)都是用Javascript编写的。 该algorithm的工作原理如下:

  1. 在客户端logging时间: var clientTime = Date.now();

  2. Ping服务器。 当服务器接收到消息时,它立即发送一个响应,其中只包含一件事情:接收到消息时服务器上的时间。

     var serverTime = Date.now(); // Send serverTime to the client 
  3. 当客户端收到服务器响应时, 立即logging时间: var clientTime2 = Date.now();

现在,我们知道当服务器收到消息时,客户端时间必须clientTimeclientTime2之间。

如果服务器在客户端时间为clientTime时接收到消息(即客户端 – >服务器请求花费了0ms),则时间增量为var delta1 = (serverTime - clientTime);

如果服务器在客户端时间为clientTime (即服务器 – >客户端响应以某种方式花了0ms)接收到消息,则时间增量为var delta2 = (serverTime - clientTime2)

因此,我们可以放心地说,时间增量介于delta1delta2之间。 现在,重复这个过程很多次,每次根据你得到的结果来缩小范围,你就可以很好地估计时间增量。

我已经在7个不同的浏览器和多台机器上testing过数百次,并且从来没有遇到任何问题。 这从来没有不一致。


但问题是,我的服务器日志显示, 偶尔会有几个人得到非常不一致的时间同步结果。 下面是一个玩家时间同步的实例:

客户端经历了上述algorithm的74个周期,并成功地将可能的时间差值的范围缩小到:[-186460,-186431],没有任何不一致。 29ms准确度

在第75次循环中,可能在第74次循环之后几秒钟,客户端计算可能时间变化的范围为:[-601,-596]。 精确度5ms ,除了与过去的74个周期非常不一致之外:这是3分钟的时间!

我会把这种情况归咎于疯狂的情况,除非它每天发生近100次……这怎么可能发生呢? 使用Date.now()时是否有可能的错误?

您的困难在于,您需要通过往返时间差异的互联网估算服务器的往返时间。 有时,这种差异意想不到,因为在临时拥塞和大型路由器缓冲区延迟单个消息的时间比正常情况下要长得多。 (Cf“bufferbloat”)

你的第二个难题是你正在使用自我报告的客户时间,这意味着如果客户有一个奇怪的时钟,它会看起来像一个往返估计出错。 另一个海报指出,互联网时间协议有时会迅速摆脱时钟,以纠正本地计时exception。

它听起来像是你需要在你的代码中进行一些过滤来考虑以前的结果,这样当你得到一个exception结果时,你不会立即接受它。

performance.now()而不是Date.now() ,因为performance.now()是单调递增的,不受时钟漂移的影响。 看到评论,感谢大家的帮助!