嵌入式NTP时间同步机制技术积累
北京华环.开发部:任晓亮 2015/11/27
项目:*******
硬件平台:NIOS2
源码:OpenSource NTP
源码网址:http://www.ntp.org/downloads.html
源码版本: ntp-4.2.6p4.tar.gz
一:编译
解压:tar –zxvf ntp-4.2.6p4.tar.gz
配置:
./configure --host=nios2-linux
--prefix=$HOME/work/nios-kernel/software_cross/ntp-4.2.6p4/_install
(--prefix=$PWD/_install)
注意配置前在建立:mkdir _install
编译:
makeCC=nios2-linux-gnu-gcc
安装:make install
二:使用
2.环境搭建好的话,可以顺利编译过
安装目录:
renxl@icserver:~/work/nios-kernel/software_cross/ntp-4.2.6p4/_install/nios2$ls
bin lib sbin share
renxl@icserver:~/work/nios-kernel/software_cross/ntp-4.2.6p4/_install/nios2/bin$ls
ntpd ntpdate ntpdc ntp-keygen ntpq ntptime ntptrace ntp-wait sntp tickadj
服务器段程序:ntpd
服务器配置文件:/etc/ntp.conf
启动方法:ntpd –g –u –p/var/ntp.pid
客户端程序:ntpdate
启动方法:ntpdate –dserver-addr
定时同步用crontab
# crontab -e
crontab: chdir(/var/spool/cron/crontabs): Nosuch file or directory
出现上面情况则执行
# mkdir -p /var/spool/cron/crontabs
三:问题
参考材料:
http://blog.chinaunix.net/uid-20680966-id-4243556.html
问题1:
编译出错:提示gcc 不支持参数"Wstrict-overflow"
解决:在源码根目录下查找这个参数,将这几个文件中的这个参数去掉,主要是configure.ac
Configure文件,(注意在执行查找的事先make distclean清理一下源码)
renxl@icserver:~/work/nios-kernel/software_cross/ntp-4.2.6p4$grep -r -n "Wstrict-overflow"
configure.ac:148: CFLAGS="$CFLAGS-Wstrict-overflow"
configure.ac:150: [if $CC can handle -Wstrict-overflow],
configure.ac:279: CFLAGS="$CFLAGS -Wstrict-overflow"
configure:7702: CFLAGS="$CFLAGS-Wstrict-overflow"
configure:7703: { $as_echo"$as_me:${as_lineno-$LINENO}: checking if $CC can handle-Wstrict-overflow" >&5
configure:7704:$as_echo_n "checking if$CC can handle -Wstrict-overflow... " >&6; }
configure:7968: CFLAGS="$CFLAGS -Wstrict-overflow"
sntp/configure.ac:81: CFLAGS="$CFLAGS-Wstrict-overflow"
sntp/configure.ac:83: [if $CC can handle -Wstrict-overflow],
sntp/configure.ac:170: CFLAGS="$CFLAGS -Wstrict-overflow"
sntp/configure:4749: CFLAGS="$CFLAGS-Wstrict-overflow"
sntp/configure:4750: { $as_echo"$as_me:${as_lineno-$LINENO}: checking if $CC can handle-Wstrict-overflow" >&5
sntp/configure:4751:$as_echo_n"checking if $CC can handle -Wstrict-overflow... " >&6; }
sntp/configure:13848: CFLAGS="$CFLAGS-Wstrict-overflow"
CommitLog:26872: enable gcc -Wstrict-overflow for gsoc_sntp
CommitLog:26886: enable gcc -Wstrict-overflow
CommitLog:27283: Enable gcc -Wstrict-overflow
CommitLog:27289: * Enable gcc -Wstrict-overflow
CommitLog:27294: enable -Wstrict-overflow, use-Wno-strict-prototypes only w/OpenSSL
CommitLog:27421: conditional to constant' warning with-Wstrict-overflow from testing if
ChangeLog:801:* Enable gcc-Wstrict-overflow for gsoc_sntp as well
ChangeLog:809:* Enable gcc-Wstrict-overflow
renxl@icserver:~/work/nios-kernel/software_cross/ntp-4.2.6p4$./configure --host=nios2-linux--prefix=$HOME/work/nios-kernel/software_cross/ntp-4.2.6p4/_install
问题二:
在运行客户端的时候出错:
Looking for host 192.168.101.180 andservice ntp
Error resolving 192.168.101.180: Servname not supported for ai_socktype (-8)
1Jan 00:10:53 ntpdate[781]: Can't find host 192.168.101.180: Servname notsupported for ai_socktype (-8)
1Jan 00:10:53 ntpdate[781]: no servers can be used, exiting
原因:因为ntp客户端访问ntp服务器是匿名访问,就是只知道ip地址不知道服务端口号所以socket连接服务器的时候socket返回错误-8就是找不到服务错误类型,需要修改一下客户端系统的系统文件,手动指定端口号,将ntp名跟端口号绑定:
root:/etc> cat services
shell 514/tcp cmd
shell 514/udp cmd
ntp 123/udp
ntp 123/tcp
问题三:
Ntpdate 192.168.101.174
1 Jan 02:32:13 ntpdate[692]:no server suitable for synchronization found
接着编译:
[root@bogon ntp-4.2.6p5]#make
ntp_loopfilter.c:520:27: error:?.OD_NANO?.undeclared (first use inthis function)
参考网上,修改 ntp_loopfilter.c:
[root@bogon ntp-4.2.6p5]#find ./ -name ntp_loopfilter.c
./ntpd/ntp_loopfilter.c
添加下面定义:
ifndef MOD_NANO
#define MOD_NANO 0x2000
#endif
问题四:
2 Jan 15:20:06ntpdate[847]: the NTP socket is in use, exiting
注释掉:port检查代码,ntpdate.c line:1773
/* rc =bind(fd[nbsock], &addr.sa, SOCKLEN(&addr));
if (rc < 0) {
if(EADDRINUSE == socket_errno())
msyslog(LOG_ERR,"the NTP socket is in use, exiting");
else
msyslog(LOG_ERR,"bind() fails: %m");
exit(1);
}*/
arm 编译:
../libntp/libntp.a(systime.o):In function `get_systime':
/home/renxl/work/nios-kernel/software_cross/ntp-4.2.6p4/libntp/systime.c:74:undefined reference to `clock_gettime'
../libntp/libntp.a(systime.o):In function `step_systime':
/home/renxl/work/nios-kernel/software_cross/ntp-4.2.6p4/libntp/systime.c:205:undefined reference to `clock_gettime'
../libntp/libntp.a(machines.o):In function `ntp_set_tod':
/home/renxl/work/nios-kernel/software_cross/ntp-4.2.6p4/libntp/machines.c:453:undefined reference to `clock_settime'
实验结果:
NTP原理:
NTP工作原理
NTP的基本工作原理如下图所示。Device A和Device B通过网络相连,它们都有自己独立的系统时钟,需要通过NTP实现各自系统时钟的自动同步。为便于理解,作如下假设:
· 在Device A和Device B的系统时钟同步之前,Device A的时钟设定为10:00:00am,Device B的时钟设定为11:00:00am。
· Device B作为NTP时间服务器,即Device A将使自己的时钟与Device B的时钟同步。
· NTP报文在Device A和Device B之间单向传输所需要的时间为1秒。
· Device A发送一个NTP报文给Device B,该报文带有它离开Device A时的时间戳,该时间戳为10:00:00am(T1)。
· 当此NTP报文到达Device B时,Device B加上自己的时间戳,该时间戳为11:00:01am(T2)。
· 当此NTP报文离开Device B时,Device B再加上自己的时间戳,该时间戳为11:00:02am(T3)。
· 当Device A接收到该响应报文时,Device A的本地时间为10:00:03am(T4)。
至此,Device A已经拥有足够的信息来计算两个重要的参数:
· NTP报文的往返时延Delay=(T4-T1)-(T3-T2)=2秒。
· Device A相对Device B的时间差offset=((T2-T1)+(T3-T4))/2=1小时。
NTP的报文格式
NTP有两种不同类型的报文,一种是时钟同步报文,另一种是控制报文(仅用于需要网络管理的场合,与本文无关,这里不做介绍)。
NTP基于UDP报文进行传输,使用的UDP端口号为123;时钟同步报文封装在UDP报文中,其格式如下图所示。
主要字段的解释如下:
· LI(Leap Indicator):长度为2比特,值为“11”时表示告警状态,时钟未被同步。为其他值时NTP本身不做处理。
· VN(Version Number):长度为3比特,表示NTP的版本号,目前的最新版本为3。
· Mode:长度为3比特,表示NTP的工作模式。不同的值所表示的含义分别是:0未定义、1表示主动对等体模式、2表示被动对等体模式、3表示客户模式、4表示服务器模式、5表示广播模式或组播模式、6表示此报文为NTP控制报文、7预留给内部使用。
· Stratum:系统时钟的层数,取值范围为1~16,它定义了时钟的准确度。层数为1的时钟准确度最高,准确度从1到16依次递减,层数为16的时钟处于未同步状态,不能作为参考时钟。
· Poll:轮询时间,即两个连续NTP报文之间的时间间隔。
· Precision:系统时钟的精度。
· Root Delay:本地到主参考时钟源的往返时间。
· Root Dispersion:系统时钟相对于主参考时钟的最大误差。
· Reference Identifier:参考时钟源的标识。
· Reference Timestamp:系统时钟最后一次被设定或更新的时间。
· Originate Timestamp:NTP请求报文离开发送端时发送端的本地时间。
· Receive Timestamp:NTP请求报文到达接收端时接收端的本地时间。
· Transmit Timestamp:应答报文离开应答者时应答者的本地时间。
· Authenticator:验证信息。
Ntp协议分析:
NTP协议格式
NTP packet = NTP header + Four TimeStamps =48byte
NTP header : 16byte
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
|LI | VN |Mode | Stratum | Poll | Precision |Root Delay | Root Dispersion | Reference Identifier |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
LeapYearIndicator : 2bit
VersionNumber : 3bit
Mode : 3 bit
Stratum : 8bit
PollInterval : 8 bit
Percision : 8bit
Root delay : 32bit
Root Dispersion : 32bit
Reference Identifier : 32bit
Four TimeStamps : 32byte
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
| Reference Timestamp |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
Reference Timestamp : 64bit
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
| Originate Timestamp |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
Originate Timestamp : 64bit
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
| Receive Timestamp |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
Receive Timestamp : 64bit
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
| Transmit Timestamp |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
Transmit Timestamp : 64bit
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
| Authenticator (optional) (96) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
以下为我捕获的ntp客户端与服务端交互的协议包:
NTP client send packet:
/* NTP header: 16 bytes */
1B 00 04 FA 00 01 00 00 00 01 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
/* Originate Timestamp */
CA 10 E7 F9 00 10 62 4D
NTP server response packet:
/* NTP header: 16 bytes */
1C 02 04 EC 00 00 00 29 00 00 07 AF CA 70 01 22
/* Reference Timestamp */
CA 10 E5 43 4D FA C7 59
/* Originate Timestamp */
CA 10 E7 F9 00 10 62 4D
/* Receive Timestamp */
CA 10 E7 F8 F0 7A 59 74
/* Transmit Timestamp */
CA 10 E7 F8 F0 7B 42 AB
NTP协议与UNIX其它时间服务的比较
网络上的校时协议有好几种:
Day Time Protocol(RFC-867)
Time Protocol(RFC-868)
Network Time Protocol (RFC-1305)
Simple Network Time Protocol(RFC-2030)
最早使用的网络时间协定是RFC-867(port 13)和RFC-868(port 37)。Day TimeProtocol送出的码是ASCII码,直接表示日期、年份、时间及时区。Time Protocol送的是32 bits的binarynumber,以二进位表示自公元1900年1月1日零时起开始的秒数,时区都是格林威治时区。而Day Time Protocol和TimeProtocol都只能表示到秒,而且并没有估算到网络的时延。在每一版的UNIX中都有rdate指令, 可向其他UNIX工作站取时间, 如果您的要求不是很高,在局域网中是适合的。
Network Time Protocol使用port 123,64 bits的binary number,前32 bits和Time Protocol一样,后32 bits用以表示秒以下的部份,并加上网络延时量的估计.理论上可以精确到到2的-32次方秒,实际使用大约只有50ms(广域网)左右,在局域网可达1ms。在实际中您应找最近而且最稳定的Server作时间源。
SNTP算是NTP的一个子集,它不像NTP可以同時和多个Server对时, 一般在Client端下使用。
如果您要求实在不高,建议您使用rdate即可,简单又方便。如果您的精确度要求在秒以下,建议您使用SNTP。如果您有一群工作站需要同步或做较精密的时间运算,那么建议您使用NTP,操作系统最好是UNIX,其次是WinNT。Win95及时的解析度只有55ms,又不稳定,不建议使用。
Ntp协议解析
NTP协议中发送和接收的数据包类似都是48个字节也可以再多一些但只需前48个字节
就可以进行计算了。数据包的内容如下
通过抓包分析出一个典型的请求数据包是这样的共48字节
1B 00 00 00 00 00 00 0000 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------------头部
D0 AF 5F F5 23 D7 0800---------------Originate Timestamp (T1)出发时间戳有效位为8 bytes
服务器端典型的回复数据包如下长度也为48字节
1C 02 00 EC 00 00 06 EA00 00 0C A2 C0 A8 33 CA----数据包头部共16 bytes
D0 AF 5E A3 F5 BD 72BC---------------Reference Timestamp
D0 AF 5F F5 23 D7 0800---------------Originate Timestamp (T1)
D0 AF 61 D7 CD 2E F911---------------Receive Timestamp ? (T2)
D0 AF 61 D7 CD 2F F4BA---------------Transmit Timestamp ?(T3)
收到数据包后本地再产生一个时间戳(T4)
这里每个返回数据前4字节为秒的整数部分后4字节为秒的小数部分
' NTP 协议中的时间是从1900年开始的。准确说秒数计数的起始时间为格林威治的1900年1月
1日0时0分0秒。我们这里另外必须有8个小时的时区补偿值。
为了代码简洁减少数制转换发现发送NTP协议协议请求包时不用发准确的发送时间戳
用个虚构的时间戳数据就可以了因此这里NTP服务器返回的请求时间戳T1只用作数据
真实性检验而由程序在发送时刻获取一个正确的时间戳作为计算用T1就成。
网络延时 = (T4-T1) -(T2-T3)
误差补偿秒数 = ((T2-T1) +(T3-T4))/2;
校对结果时间=现实时间+误差补偿秒数
这里我们一般电脑用的时间精度在1秒以内就可以了因此每个时间戳处理都只用了其整
数部分。
初始时间到时间 (“1900-01-01-0-0-0”) ' 格林威治时间1900年一月一日0时0分0秒N
UDP协议、端口123
国家授时服务中心服务器端202.72.145.44
CLIENT 一般设定
len = 48, LI=0; VN=3MODE=3 STRATUM=0,POLL=4 PREC=-6,
JAN_1970: 0X83AA7E80 //1900-1970之间的秒数
NTPFRAC(X) (4294*(X) +( (1981*(X))>>11) )
USEC(X) ( ((X)>>12) – 759*( ( ((X)>>10 ) +32768)>>16 ))
1. #define JAN_1970 0x83aa7e80 /* 2208988800 1970 - 1900 in sec
onds */
2. #define NTPFRAC(x)(4294 * (x) + ((1981 * (x))>>11))
3. #define USEC(x) (((x)>> 12) - 759 * ((((x) >> 10) + 32768) >> 16))
设置时间
获取当前时间填充到time (time_t )结构中
算法:
前端时间无意中看了NTP(Network Time Protocal)后,顿时豁然开朗.
图中T1为客户端发送请求时间, T2为服务端接收到请求时间,T3为服务端向客户端发送响应的时间,T4为客户端接收到响应的时间。d为消息在网络上来回的时间,假设消息在网络上来回时间相同(这个是必须的假设,如果没有这个假设,以下的等式就多了一个变量,那么就无法求解了。而且这个假设也是合理的,毕竟网络上传输所需的时间是很短的,一般都在毫秒级),那么单趟传输所需时间就是2/d。假设客户端和服务端时间偏差为t。则有以下等式:
T2=T1+t+d/2;
T2-T1=t+d/2;
T4=T3-t+d/2;
T3-T4=t-d/2;
联立求解即得:
d=(T4-T1)-(T3-T2);
t=((T2-T1)+(T3-T4))/2
当然,如果需要更为精确的结果,排除偶然网络不正常造成的影响,可以给求出来的d设定一个阈值D,当d>D时则让本次同步失效。
Win7开启ntp:
Server 端设置(Run--> regedit):
1、修改以下选项的键值HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\NtpServer内的「Enabled」设定为1.
该设置打开NTP服务器功能(默认是不开启NTP Server服务,除非电脑升级成为域控制站)
2、修改以下键值HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\Config\AnnounceFlags设定为5.
该设定强制主机将它自身宣布为可靠的时间源,从而使用内置的互补金属氧化物半导体 (CMOS) 时钟。
如果要采用外面的时间服务器就用默认的 a 值即可.
3、重启Win32Time服务: net stop w32Time && netstart w32Time
Client端设置(Run --> regedit):
1、修改HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\NtpClient
SpecialPollInterval 值修改成十进制43200 (单位为秒,43200为12小时)
SpecialPollTimeRemaining 值修改成[时间同步服务器],0 如:192.168.1.1,0
2、更改默认更新服务器
HKEY_LoCAL_MACHINE\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\DATETIME\SERVERS\default
3、重启Win32Time服务: net stop w32Time && netstart w32Time
六.设计思路
通过h5600代理ntp-server转发非网管设备的ntp时间请求。具体的过程如下图。
第一部分:网关跟ntp-server同步,即h5600定时启动本地的ntp-client跟指的的ntp-server同步自身时间。
第二部分:网关跟非网关,信道是DCC监控,非网关作为ntp-client发起请求,连接H5600进程的本地端口127.0.0.0:123,h5600进程将本地ip填入数据的后4字节,打扮成msdh帧通过dcc发到网关
第三部分:网关接到dcc的ntp请求后将msdh帧解包,将数据打包成以太网包,发送给本地端口127.0.0.1:123,即ntp_server服务端口号。