基础资料
基于Air105开发板:Air105 - LuatOS 文档
上手:开发上手 - LuatOS 文档
探讨重点
对官方Socket网络接口demo中NTP模块进行复现及分析,进行相关内容的学习及探讨。
实现功能
NTP协议分析及收发报文示例;
硬件准备
Air105开发板1块,面包板1块,W5500网络模块,导线若干。
接线:
W5500模块是标准SPI设备,可参考合宙Air系列开发板官方demo学习(二):camera - 摄像头:(1)-capture:中SPI接口外置sd卡的接线方式。
PIN口设置:w5500.init(spi.SPI_2, 24000000, pin.PB03, pin.PC00, pin.PE10)。 w5500.config() --默认是DHCP模式
软件版本
AIR105:LuatOS@AIR105 base 22.10 bsp V0013
TCP&UDP测试工具
软件使用
接口文档可参考:socket网络接口
基本概念(引自:百度百科)
网络时间协议,英文名称:Network Time Protocol(NTP)是用来使计算机时间同步化的一种协议,它可以使计算机对其服务器或时钟源(如石英钟,GPS等等)做同步化,它可以提供高精准度的时间校正(LAN上与标准间差小于1毫秒,WAN上几十毫秒),且可介由加密确认的方式来防止恶毒的协议攻击。NTP的目的是在无序的Internet环境中提供精确和健壮的时间服务。
NTP协议发展历史
NTP是由美国Delaware大学David L .Mills教授设计的,是最早用于网络中时钟同步的标准之一。NTP是从时间协议和ICMP时间戳报文演变而来,NTP的版本演进如下所示。
编辑切换为居中
添加图片注释,不超过 140 字(可选)
NTP报文
报文格式根据使用功能的不同分为:NTP数据报文和NTP控制报文(请参考:NTP报文格式)。
本文重点介绍数据报文。
编辑
添加图片注释,不超过 140 字(可选)
NTP报文格式如上图所示,它的字段含义参考如下:
· LI (Leap Indicator): 闰秒标识器,
长度为 2 Bits, 用来预警最近一分钟插入 1s 或者删除 1s.
LI |
Value |
含义 |
00 |
0 |
无预告 |
01 |
1 |
最近一分钟有 61s |
10 |
2 |
最近一分钟有 59s |
11 |
3 |
警告状态(时钟未同步) |
· VN (Version Number): 版本号
长度为 3 Bits, 目前最新的版本是 4, 向下兼容指定于 RFC 1305 的版本 3.
· Mode: 工作模式,
长度为 3 Bits.
点对点模式下, 客户端请求时设置此字段为 3, 服务器应答时设置此字段为 4. 广播模式下, 服务器应答设置此字段为 5.
Mode |
Value |
含义 |
000 |
0 |
保留 |
001 |
1 |
主动对称模式 |
010 |
2 |
被动对称模式 |
011 |
3 |
客户端模式 |
100 |
4 |
服务器模式 |
101 |
5 |
广播或组播模式 |
110 |
6 |
NTP控制报文 |
111 |
7 |
预留给内部使用 |
· Stratum: 系统时钟的层数,
长度为 8 Bits, 取值范围 1~16, 定义时钟的准确度. 层数为 1 的时钟准确度最高, 准确度从 1 到 16 依次递减, 阶层的上限为15, 层数为 16的时钟处于未同步状态, 不能作为参考时钟.
· NTP 获得 UTC 的时间来源可以是原子钟, 天文台, 卫星, 也可以从Internet上获取.
· stratum-0 是高精度计时设备, 例如原子钟 (如铯, 铷), GPS时钟或其他无线电时钟. 它们生成非常精确的脉冲秒信号, 触发所连接计算机上的中断和时间戳. 也称为参考 (基准) 时钟.
· stratum-1 是与 stratum-0 设备相连, 在几微秒误差内同步系统时钟的计算机.
· 时间是按 NTP 服务器的等级传播. 按照距离外部 UTC 源的远近将所有服务器归入不同的 Stratum (层) 中. Stratum-1 在顶层, 有外部 UTC 接入, 而Stratum-2 则从 Stratum-1 获取时间, Stratum-3 从 Stratum-2 获取时间, 以此类推, 但 Stratum 层的总数限制在15以内. 所有这些服务器在逻辑上形成阶梯式的架构并相互连接, 而 Stratum-1 的时间服务器是整个系统的基础.
stratum |
含义 |
0 |
未指定或者难以获得 |
1 |
主要参考(如: 无线电时钟,校正的原子时钟) |
2~15 |
第二参考(Via NTP) |
16 |
未同步状态, 不能作为参考时钟 |
· Poll: 轮询间隔时间,
长度为 8 Bits, 两个连续NTP报文之间的时间间隔, 用 2 的幂来表示,
· Precision: 系统时钟(本地时钟)的精度,
有符号整数表示的本地时钟精确度。 长度为 8 Bits, 用 2 的幂来表示。
· Root Delay: 本地到主参考时钟源的往返时间, 长度为 32 Bits, 有 15~16 位小数部分的无符号定点小数.
· Root Dispersion: 系统时钟相对于主参考时钟的最大误差, 长度为 32 Bits, 有 15~16 位小数部分的无符号定点小数.
· Reference Identifier: 参考时钟源的标识, 长度为 32 Bits.
· Reference Timestamp: 系统时钟最后一次被设定或更新的时间, 长度为 64 Bits, 无符号定点数, 前 32 Bits 表示整数部分, 后 32 Bits 表示小数部分, 理论分辨率 2^−32s.
· Originate Timestamp: NTP请求报文离开发送端时发送端的本地时间, 长度为 64 Bits.
· Receive Timestamp: NTP请求报文到达接收端时接收端的本地时间, 长度为 64 Bits.
· Transmit Timestamp: 应答报文离开应答者时应答者的本地时间, 长度为 64 Bits.
· Authenticator(Optional): 验证信息, 长度为 96 Bits, (可选信息), 当实现了 NTP 认证模式时, 主要标识符和信息数字域就包括已定义的信息认证代码 (MAC) 信息.
· NTP数据报文示例(官方demo中相关代码)
if event == socket.LINK and param == 0 then
sys.publish("NTP_ENABLE_LINK")
elseif event == socket.ON_LINE and param == 0 then
socket.tx(netc, "\xE3\x00\x06\xEC" .. string.rep("\x00", 44))
socket.wait(netc) -- 这样才会有接收消息的回调
回调函数中,发送报文请求头代码为:socket.tx(netc, "\xE3\x00\x06\xEC" .. string.rep("\x00", 44))
即为:
E3 00 06 EC 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
其中E3 00 06 EC(0-31位)为:
11 警告状态,时间未同步;
100 版本是 4;
011 客户端模式(向服务器发出请求);
00000000 未指定或难以获得
00000110 值为 6 表示最小间隔为 2^6 = 64s.
11101100 系统时钟(本地时钟)的精度。
· NTP服务器返回值
采用本地UDP工具,按16进制发送以上报文,目标服务器选择:ntp1.aliyun.com,目标端口123,连接类型UDP。
编辑切换为居中
添加图片注释,不超过 140 字(可选)
发送报文后,收到返回数据为:
24 02 06 e7 00 00 00 07 00 00 00 42 0a 89 35 07 e7 42 bf 16 4a 62 48 a3 00 00 00 00 00 00 00
00 e7 42 bf 18 8b e2 35 51 e7 42 bf 18 8c 41 49 e0
16进制40-43位为需要提取的NTP时间(不考虑请求和应答时间差的情况下,32-35位的值与40-43位相同)。
0xe742bf18转换为10进制为:3879911192。该时间是基于起算基准时间1900年的,还需要减去1900-1970的时间差(2208988800秒= (70 * 365 + 17) * 24 * 60 * 60,16进制0x83aa7e80),结果为:1670922392。
在线时间戳转换在线时间戳转换工具,可以转换为标准时间。
例程demo中还考虑了时区和时间戳回滚的情况,具体见示例代码。
·示例代码
if rbuf:used() >= 48 then
--query(40,4,true)中的true代表采用大端模式,和所用MCU有关
local tamp = rbuf:query(40,4,true)
if tamp - 0x83aa7e80 > 0 then
rtc.set(tamp - 0x83aa7e80 + 8 * 3600)
else
--2036年后,当前ntp协议会回滚
log.info("ntp 时间戳回滚")
rtc.set(0x7C558180 + tamp + 8 * 3600)
end
PS1:
大端:内存低地址存储数据高位数值,更符合人的阅读习惯。
小端:内存低地址存储数据低位数值 。
如大端模式十六进制数据 0x04,变成字符串表示存储时,0是存储在数组下表小的位置,4存储在数组下表高的位置。
PS2:最常用的国内NTP服务器
ntp1.aliyun.com
ntp.tencent.com
edu.ntp.org.cn