65.9K
CodeProject 正在变化。 阅读更多。
Home

白天,互联网时间服务类

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.91/5 (20投票s)

2004年1月28日

4分钟阅读

viewsIcon

208429

downloadIcon

4779

基于互联网参考更新系统时间的方法。

Sample Image - InternetTime.jpg

引言

Windows XP 可以自动将系统时钟与政府提供的外部互联网参考同步。此类提供了程序员控制的相同功能。您可以使用 Daytime 类获取外部日期和时间,将其与当前系统时间进行比较,并可选地更新系统时间。

背景

RFC867,由 Jonathan Postel 于 1983 年 5 月编写,描述了 Daytime 协议,这是一个简单的 ASCII 字符串,时间服务器在端口 13 上监听,用于将当前时间传达给请求者。该协议再简单不过了:一旦与时间服务器建立连接,它就会通过发送格式化的时间字符串并终止连接来响应。

字符串的格式由 NIST 设定,而不是 RFC867。字符串看起来像

        JJJJJ YY-MM-DD HH:MM:SS aa b c ddd.d UTC(NIST) *

除了基本的月、日、年、小时、分钟、秒时间外,时间服务器还返回修改的儒略日期 (JJJJJ),一个表示美国夏令时状态的指示 (aa,夏令时为 "50"),一个标志 (b,跳秒为 "1") 表示当前月将添加一个跳秒,以及其他数据 (c 为 "0" 表示时间服务器正常运行,ddd.d 表示网络延迟(以毫秒为单位)。

美国国家标准与技术研究院 (NIST) 维护着多个支持 Daytime 和其他标准(如网络时间协议 (RFC1305))的时间服务器。

Windows Internet 时间支持

现代 Windows 系统内置了对 Internet 时间服务 (ITS) 的支持。屏幕截图(上方)展示了系统时钟小程序中的第三个选项卡。如果启用,Windows 将每月或按需同步时钟。

使用代码

没有理由实例化 Daytime 对象。Daytime 类包装了四个共享方法

  • Daytime.GetTime() 作为 DateTime - 从 NIST 返回当前的 UTC 时间
  • Daytime.SecondsDifference(dt1 as DateTime, dt2 as DateTime) 作为 Integer - 以秒为单位返回两个时间之间的差值
  • Daytime.WindowsClockIncorrect() 作为 Boolean - 如果 NIST 时间与系统时间不接近,则返回 True
  • Daytime.SetWindowsClock(utcTime as DateTime) - 将 Windows 系统时间设置为 utcTime,以 UTC 表示。

调用 WindowsClockIncorrect 会检查 NIST 服务器(尝试它知道的每个服务器,直到收到响应)并将其与当前系统时间进行比较。(请注意,系统时间以协调世界时 (UTC) 存储,也称为格林尼治标准时间 (GMT) 或军用时的 Zulu。Windows 使用您指定的时间区域将 UTC 转换为本地时间。)

在调用 WindowsClockIncorrectGetTime 之后,Daytime 的两个共享变量会被更新

  • Daytime.LastHost 作为 String - 用于获取 NIST 时间的 IP 地址(如果没有任何服务器响应,则为空字符串 "")
  • Daytime.LastSysTime 作为 DateTime - 在调用 NIST 服务器之前的 Windows 系统时间,用于比较。

以下代码演示了 Daytime 类的典型用法

    If Daytime.WindowsClockIncorrect() Then
        Daytime.SetWindowsClock(Daytime.GetTime())
    End If

如果 GetTime 无法连接到时间服务器,它会返回当前系统时间。

查看代码本身,您可能想修改时间服务器列表或 NIST 时间与 Windows 时钟之间允许的时间差(秒数)。默认情况下,容差 THRESHOLD_SECONDS 为 15。它不应小于 3 秒,以考虑网络延迟和一般熵,或者您可能希望将其设置为零,以便每次都强制更新。

服务器列表来自 NIST Internet 时间服务器。正如他们建议的那样,代码使用 IP 地址而不是主机名。

您的结果可能有所不同,但这是我的位于加利福尼亚州圣何塞的计算机响应各种时间服务器的方式

53032 04-01-28 19:16:20 00 0 0 320.7 UTC(NIST) *  [129.6.15.28] Gaithersburg, MD
53032 04-01-28 19:16:21 00 0 0 917.8 UTC(NIST) *  [129.6.15.29] Gaithersburg, MD
53032 04-01-28 19:16:21 00 0 0 624.7 UTC(NIST) *  [132.163.4.101] Boulder, CO
53032 04-01-28 19:16:21 00 0 0 406.8 UTC(NIST) *  [132.163.4.102] Boulder, CO
53032 04-01-28 19:16:21 00 0 0 121.3 UTC(NIST) *  [132.163.4.103] Boulder, CO
53032 04-01-28 19:16:22 00 0 0 754.1 UTC(NIST) *  [128.138.140.44] Boulder, CO
53032 04-01-28 19:16:26 00 0 0 124.0 UTC(NIST) *  [192.43.244.18] Boulder, CO
53032 04-01-28 19:16:27 00 0 0 459.2 UTC(NIST) *  [131.107.1.10] Redmond, WA
53032 04-01-28 19:16:28 00 0 0  82.4 UTC(NIST) *  [66.243.43.21] San Jose, CA
53032 04-01-28 19:16:40 00 0 0 110.5 UTC(NIST) *  [216.200.93.8] (Abovenet) VA
53032 04-01-28 19:16:42 00 0 0 657.3 UTC(NIST) *  [208.184.49.9] San Jose, CA
53032 04-01-28 19:16:43 00 0 0 649.7 UTC(NIST) *  [207.126.98.204] Sunnyvale, CA
53032 04-01-28 19:18:03 00 0 0 441.7 UTC(NIST) *  [205.188.185.33] (AOL) VA

由于 MyDoom 病毒,也许,您可以看到此测试花费了 163 秒才能完成。因为第一个服务器很可能成功响应,所以性能通常低于一秒,但我不会尝试在紧密循环中执行此操作。

未来的增强

将来,在调用时间服务器之前测试 Internet 连接可能会很好。我假设拨号用户不想为了调整时钟而例行拨号。幸运的是,检查 LAN、DIALUP 或 OFFLINE 的代码相当简单;它在 Microsoft 知识库文章 821770 中进行了描述。

另一个可能的增强功能是调用多个时间服务器并对它们的时间进行平均,这在网络时间协议 (RFC1305) 实现中很常见。

关注点

此代码演示了一个简单的 TcpClient 会话和一个对 Windows 内核 DLL 的简单调用。

NIST 时间字符串只有两位数的年份。(还记得 Y2K 问题,它曾导致电梯冻结,飞机从天而降?)我们必须查看修改的儒略日期 (MJD) 才能确定 '04' 是 2004 年。代码按当前写法,可以处理 1900 年代(MJD 15020 到 51543)或 2000 年代(MJD >= 51544)的 NIST 日期,但当然,此代码永远不应看到早于 2004 年的日期。

历史

2004 年 1 月 27 日 AD:初始

© . All rights reserved.