【问题标题】:What time from an NTP time server should be used to set my clock?应该使用来自 NTP 时间服务器的什么时间来设置我的时钟?
【发布时间】:2021-04-09 11:39:58
【问题描述】:

我正在使用 Python3 和 ntplib https://pypi.org/project/ntplib/ 来查询 NTP 时间服务器。效果很好,但我对使用哪个提供的时间变量来正确设置我的计算机上的时钟感到困惑。

阅读第 23 页的 NTP https://www.rfc-editor.org/rfc/rfc5905 的 IETF 文档,我选择了以下任何一种:

传输时间戳(xmt):响应离开时服务器的时间 对于客户端,采用 NTP 时间戳格式。

Destination Timestamp (dst):客户端回复时的时间 从服务器到达,采用 NTP 时间戳格式。

我的解释是 xmt 是服务器发送它的那一刻的正确时间,这似乎表明我仍然需要添加从服务器到我的计算机的传输时间的时间延迟?

我不清楚 dst 时间的定义。这可能意味着:

  1. 这是已添加传输时间的 xmt 时间,因此是设置时钟的正确时间
  2. 或者是 NTP 数据包到达时我的时钟时间。如果我的时钟错了,那将不是使用的正确时间

是哪一个?

我认为#1(使用 dst)更有意义,但是在网上找到的大多数脚本都使用纯 xmt。就 ntplib 的代码而言,这意味着:

    client = ntplib.NTPClient()
    resp   = client.request(server, version=3)
    xmt    = resp.tx_time     # for the use of xmt
    # or:
    dst    = resp.dest_time   # for the use of dst

在某些测试运行中,dst 总是比 xmt 晚 3 ... 30 ms,在使用本地、区域或全局 NTP 服务器时没有明显的模式。

所以不多,但我不想做出不合逻辑的选择。

【问题讨论】:

    标签: python-3.x time ntp


    【解决方案1】:

    所有各种时间戳的知识对于理解如何更改我的计算机时间以与NTP时间服务器一致并没有太大帮助。

    经过几天的摆弄,我相信我找到了解决方案。答案是:不要使用任何时间戳——而是只使用偏移量!并且 ntplib 已经为您计算了偏移量。

    这令人惊讶,因为大多数人使用其中一个时间戳(主要是 xmt),而且,我可能错过了它,但我从未见过有人使用偏移量。

    让我们看一个例子。我使用了 3 个 NTP 服务器:一个在亚洲(最远),一个在欧洲(中等距离),一个在德国(最近)。数据包的往返时间变化很大,从几毫秒到 200 毫秒不等,与近距离或远距离目标无关。我选择了一个例子来证明我的观点(最后的代码)。我从时间戳中减去了原点,所以所有时间都相对于它们各自的原点。

        NTP Server            Type t-stamp          sec 
        asia.pool.ntp.org     orig                  0.000
        asia.pool.ntp.org     recv                  0.004
        asia.pool.ntp.org     tx                    0.004
        asia.pool.ntp.org     dest                  0.014
        asia.pool.ntp.org     offset               -0.003
    
        europe.pool.ntp.org   orig                  0.000
        europe.pool.ntp.org   recv                  0.008
        europe.pool.ntp.org   tx                    0.008
        europe.pool.ntp.org   dest                  0.020
        europe.pool.ntp.org   offset               -0.002
    
        de.pool.ntp.org       orig                  0.000
        de.pool.ntp.org       recv                  0.008
        de.pool.ntp.org       tx                    0.008
        de.pool.ntp.org       dest                  0.019
        de.pool.ntp.org       offset               -0.002
    

    在亚洲示例中,往返总时间为 14 毫秒。发送时钟差为 4ms,接收时钟差为 10ms。因此偏移量为 (4 - 10)/2 = -3ms。

    现在要做的所有重要假设是往返的旅行时间是相同的!那么我可以说,如果我把这个偏移量加到我的计算机时间上,两个时间都会变成一样的!

    同样适用于欧洲:往返 20 毫秒,偏移:(8 - 12)/2 = -2 毫秒,德国:往返 19 毫秒,偏移:(8 - 11)/2 = -1.5 毫秒。

    由于 lib 已经给出了偏移量,所以您只需将这个带符号的偏移量添加(!,而不是减去)您的计算机时间。

    然后我在使用德国(最近的)NTP 服务器大约半小时时记录了 ntplib-offsets:

    'Ambient' 是 ntplib 报告的偏移量,单位为 ms。

    看起来我的电脑设置得很好,它的时间大多在 NTP 时间的 5 毫秒内。但是有一些显着的偏移高达 70 毫秒!在一个程序中,我本可以选择这个——显然是错误的——时间。

    显而易见的问题:如何确保在时钟调整中不会出现异常值?

    代码的基本部分:

        for i, ntpserver in enumerate(NTP_SERVERS):
        ntps     = []
        client   = ntplib.NTPClient()
        try:
            response = client.request(ntpserver, version=4, timeout=0.5) # latest NTP version = 4
    
            orig = response.orig_time
            recv = response.recv_time
            tx   = response.tx_time
            dest = response.dest_time
            offs = response.offset
            ntps.append( ["orig"     , orig - orig])
            ntps.append( ["recv"     , recv - orig])
            ntps.append( ["tx  "     , tx   - orig])
            ntps.append( ["dest"     , dest - orig])
            ntps.append( ["offset"   , offs])
           
            for  a in ntps:
                print("{:20s}  {:15s}  {:10.3f} ".format(ntpserver, a[0], a[1]))
           
        except Exception as e:
            msg = fncname + "FAILED with Exception: {}".format(e)
            edprint(msg)
    

    【讨论】:

      【解决方案2】:

      NTP 响应有 5 个时间戳

      Field name Name Description
      ref_timestamp Reference Timestamp Time when the system clock was last set or corrected, in NTP timestamp format
      orig_timestamp originate timestamp (T1) Time at the client when the request departed for the server, in NTP timestamp format.
      recv_timestamp receive timestamp (T2) Time at the server when the request arrived from the client, in NTP timestamp format.
      tx_timestamp transmit timestamp (T3) Time at the server when the response left for the client, in NTP timestamp format.
      dest_timestamp Destination timestamp (T4) Time at the client when the reply arrived from the server, in NTP timestamp format.

      每个时间戳字段都有一个关联的时间字段,它是作为系统时间的时间戳,它是自纪元以来的时间,以秒为单位。

      Field name Description
      ref_time reference timestamp as system time
      orig_time originate timestamp as system time
      recv_time receive timestamp as system time
      tx_time transmit timestamp as system time
      dest_time destination timestamp as system time

      偏移量是您的本地时钟与 NTP 服务器时钟之间的差异,即以秒为单位校正本地时钟以匹配服务器时钟的量。

      偏移量 = ((recv_timestamp - orig_timestamp) + (tx_timestamp - dest_timestamp))/2

      偏移量 = ((T2 - T1) + (T3 - T4))/2

      例子:

      import ntplib
      from datetime import datetime
      
      client = ntplib.NTPClient()
      server = '0.pool.ntp.org'
      resp = client.request(server, version=3)
      
      print("offset", resp.offset)
      print("orig_time:", datetime.utcfromtimestamp(resp.orig_time).strftime('%Y-%d-%m %H:%M:%S.%f'))
      print("recv_time:", datetime.utcfromtimestamp(resp.recv_time).strftime('%Y-%d-%m %H:%M:%S.%f'))
      print("tx_time  :", datetime.utcfromtimestamp(resp.tx_time).strftime('%Y-%d-%m %H:%M:%S.%f'))
      

      输出

      offset 0.009677410125732422
      orig_time: 2021-06-01 00:06:10.553593
      recv_time: 2021-06-01 00:06:10.665957
      tx_time  : 2021-06-01 00:06:10.665980
      

      正值偏移表示服务器时钟比本地时钟提前该秒数。负值表示本地时钟提前。

      在上面的输出中,服务器在 00:06:10.665957 (recv_time) 收到了时间请求,并在 00:06:10.665980 (tx_time) 回复了回复,这需要 23 微秒才能完成。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-03-17
        • 2019-11-29
        • 2013-04-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-02-27
        • 1970-01-01
        相关资源
        最近更新 更多