NTP协议

NTP(Network Time Protocol)

        NTP(Network Time Protocol):是一种用于同步计算机系统时间的协议。

        NTP 通过分层的时间服务器架构,确保网络中所有设备的时间保持一致,精度可达毫秒甚至微秒级别,是互联网上最广泛使用的时间同步协议。

NTP就是上述过程的网络版:

设备(客户端) → 通过网络 → 问NTP服务器 → "现在几点?"

NTP服务器   → 回复一个精确时间戳 → 设备据此调整时钟

NTP报文格式(48B):

字节偏移

字段名称

大小

说明

0

LI + VN + Mode

1字节

闰秒+版本+模式

1

Stratum

1字节

服务器层级

2

Poll

1字节

轮询间隔

3

Precision

1字节

精度

4-7

Root Delay

4字节

根延迟

8-11

Root Dispersion

4字节

根离散度

12-15

Reference ID

4字节

参考源标识

16-23

Reference Timestamp

8字节

上次同步时间

24-31

Origin Timestamp

8字节

客户端发送时间(原样返回)

32-39

Receive Timestamp

8字节

服务器收到时间

40-47

Transmit Timestamp

8字节

服务器发送时间

字段具体含义:

字段名称

长度

含义说明

LI (Leap Indicator)

2 bits

闰秒指示器。警告客户端关于即将到来的闰秒(由于地球自转不均匀,UTC偶尔需要加1秒或减1秒)。

00: 无警告 01: 最后一分钟是59 10: 最后一分钟是61  11: 时钟未同步(告警状态)

VN (Version Number)

3 bits

NTP版本号。目前常用的是版本 4(二进制 100)。

Mode

3 bits

工作模式。标识这个包是客户端发的还是服务端发的。3: 客户端 4: 服务器 6: 广播/组播等等

Stratum

8 bits

层级。表示时钟距离标准参考时钟(如原子钟、GPS)有多远。0: 无效或 unspecified  1: 直接连接参考时钟(如带GPSNTP服务器) 2-15: 逐级向下同步的层级 16: 表示时钟未同步

Poll

8 bits

轮询间隔。表示连续两次NTP请求之间的最大时间间隔。这是一个以2为底的指数(如6表示 64秒)。

Precision

8 bits

精度。表示本地时钟的精度,也是以2为底的指数(通常为负数,如-10表示约1毫秒精度)。

Root Delay

32 bits

根延迟。从当前服务器到主参考时钟(Stratum 1)之间的总往返延迟时间(毫秒级)。

Root Dispersion

32 bits

根离散度。表示相对于主参考时钟的最大误差估计值。

Reference ID

32 bits

参考标识符。标识当前服务器是从哪里同步时间的。Stratum 1时通常是GPSATOMASCII码;

Stratum 2及以上时通常是上游服务器的IP地址。

Reference Timestamp

64 bits

参考时间戳。本地时钟最后一次被设置或校正的时间(NTP时间戳格式)。

Origin Timestamp

64 bits

源时间戳。客户端发送请求时的本地时间(NTP时间戳格式)。

Receive Timestamp

64 bits

接收时间戳。服务器收到客户端请求时的本地时间(NTP时间戳格式)。

Transmit Timestamp

64 bits

发送时间戳。服务器把响应包发给客户端时的本地时间(NTP时间戳格式)。

NTP是如何利用这些时间戳计算网络延迟的?

NTP之所以需要这4个时间戳,是为了消除网络传输带来的误差。计算公式如下(T1到T4均为时间点):

T1 (Origin) = 客户端发包时间

T2 (Receive) = 服务器收包时间

T3 (Transmit) = 服务器回包时间

T4 (到达客户端时间) = 客户端收到回复时的本地时间(这个不在包里,是客户端自己记录的)

通过这4个时间点,客户端可以算出:

  1. 网络往返延迟 = (T4 - T1) - (T3 - T2)
  2. 客户端与服务器的时间差 = ((T2 - T1) + (T3 - T4)) / 2

算出时间差后,客户端就会将这个差值(可能带有小数,即NTP时间戳的后32位)转换为操作系统支持的Unix时间戳格式,并调整系统时钟。

当NTP客户端和服务器(网络层)通过网络通信时,它们在数据包中交换的只有NTP时间戳。但在操作系统层面需要转换:当操作系统(如Linux/Windows)接收到NTP服务器的回复后,操作系统的内核或NTP守护进程(如ntpd/chronyd)会将收到的“NTP时间戳”在内存中转换为“Unix时间戳”,然后再设置到系统时钟中:

NTP时间戳

为什么有NTP时间戳和其他时间戳(以Unix为例)?

它们诞生于不同的历史背景,服务于不同的层级(网络层 vs 操作系统层):

1. NTP时间戳(诞生于1985年之前)

结构:64位长整型。前32位表示秒数,后32位表示小数秒(即纳秒/皮秒级精度),从1900年1月1日 00:00:00 UTC开始。

原因:NTP被设计用于跨网络同步高精度时间,需要极高的分辨率(小数秒)。选择1900年是因为当时设计NTP时,32位无符号整数能表示约136年,刚好覆盖到2036年(即NTP的“2036年溢出问题”),在当时看来是足够安全的。

2. Unix时间戳(诞生于1970年代初)

结构:通常是一个32位或64位整数,表示自1970年1月1日 00:00:00 UTC以来的整秒数(早期Unix系统不需要亚秒级精度)。

原因:Unix系统在设计时,为了在有限的硬件资源下方便计算日期,选择了1970年作为起点,且只记录整秒。著名的“Y2038问题”就是指32位Unix时间戳在2038年会溢出(靠物理升级到 64 位解决)。

NTP时间戳是为了网络高精度传输设计的;Unix时间戳是为了操作系统内部简单计算设计的。两者起点不同、精度不同,所以需要转换。

     其他的时间戳还有很多,比如:

  • Windows系统时间戳:起点是1601年1月1日,以100纳秒为间隔,存储在64位结构中。
  • PTP时间戳(IEEE 1588 精密时间协议):起点是1970年1月1日(TAI国际原子时,非UTC),精度可达纳秒甚至皮秒级,用于金融交易和5G基站等高精尖领域。
  • GPS时间戳:起点是1980年1月6日,连续计数不含闰秒。
  • Mac/Apple Cocoa时间戳:起点是2001年1月1日,以秒为单位。

所以在windows上用Python (是一门跨平台语言,在底层实现CPython中做了转换)写NTP相关的代码时是转化成Unix时间戳,到 C/C++ (调用Windows API)转化成Windows系统时间戳。

NTP-Unix转换公式:

  NTP时间戳 = (Unix时间戳 + 2208988800) << 32 | 小数部分

  Unix时间戳 = (NTP时间戳 >> 32) – 2208988800

NTP的2036年溢出问题

NTP的2036年溢出问题的解决(v4版)并没有修改数据包结构(为了向后兼容,老设备依然能解析)。它的解决逻辑非常巧妙,记录在 RFC 5905 中(软件层面的“纪元推断”和加法修正),可以参考链接如下:

https://www.rfc-editor.org/info/rfc5905/#page-13

1.定义新的纪元

当 2036 年到来,32位秒数溢出归零后,NTP 并不认为这是 1900 年,而是定义这是一个新的纪元。(有一种三体的感觉)

第一个纪元:1900年 - 2036年

第二个纪元:2036年 - 2172年

第三个纪元:2172年 - 2308年
以此类推,每 136 年一个纪元。

2.客户端如何推断现在是哪个纪元?

NTP 协议规定:客户端和服务器在通信时,默认双方处于同一个纪元。客户端在发包时,知道自己本地的大致时间(比如客户端知道现在是 2036 年 5 月)。当它收到服务器发来的时间戳(秒数部分是一个很小的数字,比如 1000万秒)时,客户端会这样算:

“现在是 2036 年,处于第二个纪元。服务器发来的小数字,一定是第二个纪元里的时间。”

于是客户端自动把这个小数字加上 2^32秒的偏移量,还原出正确的时间。

3.跨纪元过渡期怎么办?(2035年-2037年)
        但如果在 2035 年,客户端(还在第一个纪元末尾)向服务器请求,但服务器因为某种原因已经翻到了第二个纪元(返回了很小的秒数),客户端怎么判断?

规则: 如果客户端收到的时间戳,比客户端自己当前的时间小很多(比如相差超过 68 年),客户端就会自动给收到的时间戳加上一个 2^32(约136年),看看加上之后是不是合理。如果加上之后刚好和本地时间接近,就说明服务器已经进入了下一个纪元。

NTP采用UDP协议

NTP传输采用的是UDP协议,因为NTP 不需要 TCP 的“可靠性”和“顺序性”,它需要的是 UDP 极低的协议开销和网络延迟以及“无状态的并发处理能力”。对于时间同步来说,“快速拿到一个最新的时间快照”比“确保每一个包都送达”重要得多。

参考资料

NTP 协议 | 菜鸟教程

https://www.rfc-editor.org/info/rfc5905

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值