ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

NTP协议

NTP协议 NTPNetwork Time ProtocolNTPNetwork Time Protocol是一种用于同步计算机系统时间的协议。NTP 通过分层的时间服务器架构确保网络中所有设备的时间保持一致精度可达毫秒甚至微秒级别是互联网上最广泛使用的时间同步协议。NTP就是上述过程的网络版设备(客户端) → 通过网络 → 问NTP服务器 → 现在几点NTP服务器 → 回复一个精确时间戳 → 设备据此调整时钟NTP报文格式48B字节偏移字段名称大小说明0LI VN Mode1字节闰秒版本模式1Stratum1字节服务器层级2Poll1字节轮询间隔3Precision1字节精度4-7Root Delay4字节根延迟8-11Root Dispersion4字节根离散度12-15Reference ID4字节参考源标识16-23Reference Timestamp8字节上次同步时间24-31Origin Timestamp8字节客户端发送时间(原样返回)32-39Receive Timestamp8字节服务器收到时间40-47Transmit Timestamp8字节服务器发送时间各字段具体含义字段名称长度含义说明LI (Leap Indicator)2 bits闰秒指示器。警告客户端关于即将到来的闰秒由于地球自转不均匀UTC偶尔需要加1秒或减1秒。00:无警告01:最后一分钟是59秒10:最后一分钟是61秒11:时钟未同步告警状态VN (Version Number)3 bitsNTP版本号。目前常用的是版本4二进制100。Mode3 bits工作模式。标识这个包是客户端发的还是服务端发的。3:客户端4:服务器6:广播/组播等等Stratum8 bits层级。表示时钟距离标准参考时钟如原子钟、GPS有多远。0:无效或unspecified 1:直接连接参考时钟如带GPS的NTP服务器2-15:逐级向下同步的层级16:表示时钟未同步Poll8 bits轮询间隔。表示连续两次NTP请求之间的最大时间间隔。这是一个以2为底的指数如6表示64秒。Precision8 bits精度。表示本地时钟的精度也是以2为底的指数通常为负数如-10表示约1毫秒精度。Root Delay32 bits根延迟。从当前服务器到主参考时钟Stratum 1之间的总往返延迟时间毫秒级。Root Dispersion32 bits根离散度。表示相对于主参考时钟的最大误差估计值。Reference ID32 bits参考标识符。标识当前服务器是从哪里同步时间的。Stratum 1时通常是GPS、ATOM等ASCII码Stratum 2及以上时通常是上游服务器的IP地址。Reference Timestamp64 bits参考时间戳。本地时钟最后一次被设置或校正的时间NTP时间戳格式。Origin Timestamp64 bits源时间戳。客户端发送请求时的本地时间NTP时间戳格式。Receive Timestamp64 bits接收时间戳。服务器收到客户端请求时的本地时间NTP时间戳格式。Transmit Timestamp64 bits发送时间戳。服务器把响应包发给客户端时的本地时间NTP时间戳格式。NTP是如何利用这些时间戳计算网络延迟的NTP之所以需要这4个时间戳是为了消除网络传输带来的误差。计算公式如下T1到T4均为时间点T1 (Origin) 客户端发包时间T2 (Receive) 服务器收包时间T3 (Transmit) 服务器回包时间T4 (到达客户端时间) 客户端收到回复时的本地时间这个不在包里是客户端自己记录的通过这4个时间点客户端可以算出网络往返延迟 (T4 - T1) - (T3 - T2)客户端与服务器的时间差 ((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) – 2208988800NTP的2036年溢出问题NTP的2036年溢出问题的解决v4版并没有修改数据包结构为了向后兼容老设备依然能解析。它的解决逻辑非常巧妙记录在 RFC 5905 中软件层面的“纪元推断”和加法修正可以参考链接如下https://www.rfc-editor.org/info/rfc5905/#page-131.定义新的纪元当 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
返回列表