我开发了一个基于HTML5的多人游戏,它需要在服务器和客户端之间保持合理准确的时间同步。大多数情况下,我使用的算法非常精确——它只是估计客户端与服务器之间的时间差,即服务器当前时间与客户端当前时间之间的差异。例如,如果服务器时间比客户端时间早5秒,时间差就是5000毫秒。
客户端和服务器(node.js)都是用Javascript编写的。该算法的工作原理如下:
如果服务器在客户端时间为clientTime时(即客户端->服务器请求以某种方式花费了0ms),则时间差为var delta1 =(serverTime-clientTime);
如果服务器在客户端时间为clientTime2时(即服务器->客户端响应以某种方式花费了0ms),则时间差为var delta2 =(serverTime-clientTime2)。
因此,我们可以安全地说,时间差在delta1和delta2之间。现在,重复这个过程多次,每次根据得到的结果缩小范围,就可以相当准确地估计时间差。
我已经在7个不同的浏览器和多台机器上测试了数百次,并且从来没有出现过任何问题。它从未不一致过。
问题在于,我的服务器日志显示,偶尔会有一些人得到极度不一致的时间同步结果。以下是一个玩家时间同步的实际示例:
客户端经历了74个以上算法周期,并成功将可能的时间差范围缩小到:[-186460,-186431],没有任何不一致。29ms的精度。
在第75个周期,在第74个周期之后的几秒钟内,客户端计算出可能的时间差范围为:[-601,-596]。5ms的精度,除了与过去74个周期极其不一致外。它比过去慢了3分钟!
我会把这归咎于疯狂的边缘情况,但几乎每天都会发生这种情况……怎么可能呢?在使用Date.now()时是否有可能出现任何错误?
客户端和服务器(node.js)都是用Javascript编写的。该算法的工作原理如下:
Record time on the client:
var clientTime = Date.now();
Ping the server. When the server receives the message, it immediately sends a response containing just one thing: the time on the server when the message was received.
var serverTime = Date.now(); // Send serverTime to the client
When the client receives the server response, immediately record the time:
var clientTime2 = Date.now();
如果服务器在客户端时间为clientTime时(即客户端->服务器请求以某种方式花费了0ms),则时间差为var delta1 =(serverTime-clientTime);
如果服务器在客户端时间为clientTime2时(即服务器->客户端响应以某种方式花费了0ms),则时间差为var delta2 =(serverTime-clientTime2)。
因此,我们可以安全地说,时间差在delta1和delta2之间。现在,重复这个过程多次,每次根据得到的结果缩小范围,就可以相当准确地估计时间差。
我已经在7个不同的浏览器和多台机器上测试了数百次,并且从来没有出现过任何问题。它从未不一致过。
问题在于,我的服务器日志显示,偶尔会有一些人得到极度不一致的时间同步结果。以下是一个玩家时间同步的实际示例:
客户端经历了74个以上算法周期,并成功将可能的时间差范围缩小到:[-186460,-186431],没有任何不一致。29ms的精度。
在第75个周期,在第74个周期之后的几秒钟内,客户端计算出可能的时间差范围为:[-601,-596]。5ms的精度,除了与过去74个周期极其不一致外。它比过去慢了3分钟!
我会把这归咎于疯狂的边缘情况,但几乎每天都会发生这种情况……怎么可能呢?在使用Date.now()时是否有可能出现任何错误?