`
zhanghh315
  • 浏览: 16848 次
  • 性别: Icon_minigender_2
  • 来自: 长春
社区版块
存档分类
最新评论

客户端实现准确的服务器时间同步 [转]

 
阅读更多

一、问题描述

需要解决的问题很简单,就是如何在页面上比较准确的显示服务器时间。目前比较常用的方法就是根据基准时间使用setTimeout或 setInterval来计算最新的时间,这样的问题在于setTimeout与setInterval的时间精度比较低,经测试一分钟大概能相差几秒 (与电脑性能以及运行的任务也相关),这样的精度在某些需求下是无法满足的。除此之外,如果要获得比较准确的时间可以定期与服务器进行校准,只是这样实现 的成本大一些。

 

本文尝试了一种改良的客户端实现时间同步的方式,具有以下的特点:

  • 1. 根据基准时间进行纯客户端计算,无需服务器校准
  • 2. 时间精度与客户端系统时间保持一致
  • 3. 不受客户端时间与服务器时间不同步造成的影响
  • 4. 不受客户端系统时间发生修改造成的影响
  • 5. 不受页面前进后退造成的影响

二、具体实现

1. 为了解决原方案中的时间精度问题,这里不再使用setTimeout和setInterval来直接计算时间,而是直接使用客户端时间(CT)。不过客户 端时间很可能与服务器时间(ST)不同步,这需要在页面加载的时候计算出客户端与服务器的时间差值(ΔT),这样只需在客户端时间上做一下修正即可得到准 确的服务器时间(ST’ = CT - ΔT)。

2. 由于客户端时间很可能被用户修改,因此直接按照步骤1中的方式计算,一旦用户修改了时间,计算出来的服务器时间也将随之发生变化。这就需要检测出客户端时 间的变化并消除这个变化。检测的方法很简单,即在每个计算周期(T)都将当时的客户端时间(CT2)与上一个周期的客户端时间(CT1)做比较,一旦两个 周期的差值(ΔT’ = CT2 - CT1 - T)大于某个预设值(S)时就将差值(ΔT’)加入到ΔT中,即此时的ΔT = ΔT + ΔT’。之所以需要设置一个预设值,是因为每个周期的时间本身不是固定的(依赖于setTimeout),因此ΔT’并不会等于0,如果每次都将 setTimeout造成的误差作为CT与ST之间的误差将会造成计算不准确。经过以上的计算,用户修改时间后将不会对计算结果产生影响。

3. 经JK提醒,完成以上两步还有一个问题,当用户离开当前页面之后后退回页面时,时间计算不准确。问题在于基准时间是服务器给的,在第一次进入页面的时候确 定,当用户后退回当前页面时,基准时间并没有变,这样会导致重新从过期的基准时间开始计算,导致不准确。需要解决这个问题就是需要解决跨页面的数据存储问 题,这在之前的《Ajax应用中浏览器历史的兼容性解决方案》一 文中已经说明,即通过表单元素来记忆。具体的实现方案是,页面第一次加载时创建两个input,一个用于存储最近一次的客户端时间,一个用于存储最近一次 的基准时间。如果发现已经存在input(前进、后退、非强制刷新)则比较上一次的客户端时间与当前客户端时间,如果其差值大于某个预设值则像步骤2中一 样进行校准,只不过使用的将是最新的基准值。

具体的代码实现如下

 

  1.  /*定义*/    
  2.     var SyncTimer = (function(){    
  3.         /*跨页面数据存储器*/    
  4.         //存储最近一次的客户端时间,用于在页面前进、后退时进行时间矫正    
  5.         var memoryElementID = 'sync_timer_memory_el';    
  6.         //存储矫正后的最新基准时间,当页面前进、后退到当前页面时会以此值为新的基准时间    
  7.         var memoryBaseTimeElementID = 'sync_timer_memory_base_time_el';    
  8.         document.write('   
  9. <input type="text" id="' + memoryElementID + '">');    
  10.         document.write('   
  11. <input type="text" id="' + memoryBaseTimeElementID + '">');    
  12.         return{    
  13.             /*  
  14.              * @param { Integer } baseTime 基准时间  
  15.              * @param { Function } updater 时间更新时的监听器  
  16.              * @param { Integer } interval 校准计算周期时长,默认为200ms。  
  17.              * @param { Integer } threshold 两个检查周期之间的时间误差(差值-周期时长)如果大于阈值则视为客户端时间有调整,默认为500ms。  
  18.              */    
  19.             run: function(baseTime,updater,interval,threshold){    
  20.                 interval = interval || 200;    
  21.                 threshold = threshold || 500;                       
  22.     
  23.                 var memoryEl = document.getElementById(memoryElementID);    
  24.                 var baseTimeEl = document.getElementById(memoryBaseTimeElementID);    
  25.     
  26.                 /*前进、后退或刷新,则矫正baseTime*/    
  27.                 if( memoryEl.value != '' ){    
  28.                     //计算当前客户端时间与上次存储的客户端时间之差,如果差值超过阈值则更新基准时间    
  29.                     var diff = +new Date - parseInt(memoryEl.value);    
  30.                     if( Math.abs( diff ) - interval > threshold ){    
  31.                         baseTime = parseInt(baseTimeEl.value);    
  32.                         baseTime += diff;    
  33.                     }    
  34.                 }    
  35.     
  36.                 var ct = +new Date;    
  37.                 var diff = ct - baseTime;    
  38.                 var pt = ct,cct;    
  39.     
  40.                 (function(){    
  41.                     cct = +new Date;    
  42.                     /*计算当前计算周期与上一个计算周期的时间差,如果差值大于设定的阈值则进行矫正(处理客户端时间调整的情况)*/    
  43.                     var secDiff = cct - pt;    
  44.                     if( Math.abs( secDiff ) - interval > threshold ){    
  45.                         diff += (secDiff - interval);    
  46.                     }    
  47.                     var fixedTime = cct - diff;    
  48.                     updater( fixedTime );    
  49.                     pt = memoryEl.value = cct;    
  50.                     baseTimeEl.value = fixedTime;    
  51.                     setTimeout(arguments.callee,interval);    
  52.                 })();    
  53.             }    
  54.         }    
  55.     })();    
  56.     /*使用*/    
  57.     window.onload = function(){    
  58.         var serverTime = parseInt($('dateWrapper').getAttribute('date'))*1000;    
  59.     
  60.         SyncTimer.run(serverTime,function(date){    
  61.             var d = new Date(date);    
  62.             $('dateWrapper').innerHTML = d.format('yyyy-MM-dd hh:mm:ss');    
  63.             $('dateWrapper').setAttribute('date',parseInt(date/1000));    
  64.         });    
  65.     }    

 

三、总结

  • 总体实现还是比较麻烦,如果对时间精度要求不高可不必这么做。
  • 还有一种情况未解决:用户从当前页面进入别的页面后修改客户端时间,之后后退到当前页面,此时时间计算不正确,但是暂时未找到解决方案。
  • 此外发现两个有意思的东西:1. 在Firefox下如果将客户端时间改慢会导致setInterval停止运行,而setTimeout则不会;2. 在Chrome中,当用户修改了客户端时间后,setInterval中取到的Date的值并不会随用户的修改而修改。
分享到:
评论
1 楼 zhanghh315 2014-04-16  
一直在纠结淘宝的秒杀究竟是怎么做到客户端和服务器端时间同步的,有知道的,欢迎留言讨论

相关推荐

    AD域中客户端时间与服务器时间不同步的解决办法

    ### AD域中客户端时间与服务器时间不同步的解决办法 #### 概述 在Active Directory(AD)域环境中,确保所有客户端与服务器之间的时间同步至关重要。时间的不同步不仅会影响用户的日常操作体验,还可能导致安全...

    域客户端同步时间服务器组策略设置

    为了实现客户端与域控制器的时间同步,我们需要在域控制器上进行一些设置。 首先,我们需要将域控制器配置为不使用外部时间源,然后更改域控制器上的公告标志。在注册表编辑器中,我们可以对相应的键值进行修改,...

    客户端和服务端时间同步

    客户端和服务端时间同步,实现了时间同步问题

    windows_2008_R2上建立NTP_Server和客户端实现时间同步

    NTP 服务器和客户端时间同步在 Windows 2008 R2 上的实现 NTP(Network Time Protocol,网络时间协议)是一种协议,用于同步计算机的时间,以确保计算机的时间是一致的。 在 Windows 2008 R2 上建立 NTP 服务器和...

    C++实现时间同步服务器

    通过注册表,实时本机同时作为时间服务器,或者客户端,实现时间同步。 实现平台,Windows2000,XP,Win7。可以与任何一台服务器相连,也可以自己也自己相连。需要完全C++代码的加QQ:182392810

    NTP服务器的配置以及客户端自动同步

    时间同步的实现 时间同步可以通过修改 `/etc/sysconfig/ntpd` 文件中的 `Sync_hwclock=no` 为 `Sync_hwclock=yes` 来实现。然后,可以使用 `date` 命令来修改日期和时间,例如 `date –s mm/dd/yyyy` 修改日期,`...

    Indy控件实现服务器与客户端的时间同步

    比如,防止用户修改当前时间,造成数据逻辑混乱,客户端使用的时间应为服务器时间。 如何处理呢,我们可以使用Delphi Indy组件中的 TIdDayTimeServer和TIdDayTime一对组件。 TIdDayTimeServer用于服务器端,...

    windows设置时间服务器以及客户端同步.rar

    在“压缩包子文件的文件名称列表”中提到的文件可能是这样一个批处理脚本,用于修改注册表设置以保持客户端与服务器的时间同步。 在客户端计算机上,可以使用以下步骤来配置时间同步: 1. 将服务器配置为权威时间...

    NTP时间同步客户端程序C#源码

    3. 客户端接收到响应后,计算出服务器时间与本地时间的差异,并据此调整本地系统时间。 在C#中,实现NTP客户端通常会用到System.Net.NetworkInformation命名空间中的NetworkInformation类,或者直接使用第三方库如...

    利用socket实现客户端服务器之间简单通信

    1. 第一次握手:客户端发送一个带有SYN(同步序列编号)标志的数据包给服务器,请求建立连接。 2. 第二次握手:服务器接收到SYN包后,回复一个SYN+ACK(确认)的数据包,表示同意建立连接,并且会设置自己的序列号和...

    局域网时间同步(服务器+客户端)

    在这种情况下,开发者创建了一个简化版的客户端,它仅与一个指定的服务器进行通信,以实现更简洁、定制化的时间同步。 "vc版本"可能是使用Microsoft Visual C++编写的客户端程序,这是一个常用的Windows应用程序...

    同步Socket(客户端与服务器端)

    同步Socket,也称为阻塞Socket,...综上所述,同步Socket是实现客户端与服务器端数据交换的基础工具,它的主要特点是简单易用但可能会影响程序的并发性能。理解和熟练掌握同步Socket的使用,对于进行网络编程至关重要。

    简单帧同步客户端和服务器端

    - 为了保证一致性,还需要处理时间同步问题,例如使用时间戳或者同步计数器。 5. **优化策略**: - 为了减少网络负载,可以选择性地同步关键对象的状态,而非所有细节。 - 可以采用平滑插值(Lerp)等技术来平滑...

    和php空间服务器时间同步.rar

    "和php空间服务器时间同步.rar"这个压缩包可能包含了与PHP编程语言相关的资料,特别是关于如何将Delphi客户端应用程序与PHP运行的服务器进行时间同步的方法。下面我们将详细探讨这个主题。 首先,理解时间同步的...

    C# 从NTP服务器获取时间并同步本地时间WinForm

    本项目"**C# 从NTP服务器获取时间并同步本地时间WinForm**"提供了一个使用C#编程语言实现的WinForm应用,其功能是自动从NTP服务器获取时间,并将获取到的准确时间同步到本地计算机。下面将详细介绍这个项目涉及到的...

    DELPHI 7 使用TService 制作的时间同步服务器客户端,可安装在windows服务中

    客户端接收到响应后,会对比本地时间和服务器时间,然后调整本地系统的时钟以匹配服务器时间。这个过程可能需要考虑网络延迟和其他因素,以确保时间同步的准确性。 6. **安全性与可靠性**:为了保证服务的稳定性和...

    与NTP服务器时间同步的类

    本篇将详细讲解与NTP服务器时间同步的相关知识点,以及如何利用提供的源代码实现这一功能。 首先,NTP是一种互联网标准,设计目的是使计算机时间在全局网络上保持一致。它通过交换时间戳数据包来校准本地系统时间,...

    服务器端世界时间(UTC)转换客户端时区时间

    1. **世界时间(UTC)**:全称为Coordinated Universal Time,即协调世界时,是一种国际标准时间基准,用于标准化世界各地的时间同步。UTC时间不考虑夏令时的影响,它是基于原子钟的标准时间。 2. **本地时间**:指的...

    Server客户端与服务器相互问候的服务器实现

    3. **服务器端编程**:实现服务器端的问候功能,通常涉及编程语言的选择和网络库的使用。例如,使用Python的socket库可以创建一个基础的TCP服务器,监听特定端口,接收到客户端连接后,发送预先定义的问候消息。同样...

Global site tag (gtag.js) - Google Analytics