如何与时间服务器进行时间同步 系统时间同步服务器

在互联网上发布精确时间,要依靠一个协议,叫NTP(Network TimeProtocol)协议,中文一般称为网络时间协议,互联网上有许多时间服务器,负责提供精确时间。

1、NTP协议的基本原理

假定时间服务器是A,我们的机器是B,则同步过程如下进行:

t4和t1是以B的时间标准记录的时间戳,其差t4-t1表示整个消息传递过程所需要的时间间隔;t3和t2是以A机的时间标准记录的时间戳,其差t3-t2表明消息传递过程在A机逗留的时间,那么(t4-t1)-(t3-t2)应该就是信息包从B到A,再从A传回B的时间(中间刨去了在A机的逗留时间),如果假定信息包从A到B和从B到A所用的时间一样,那么,从A到B或者从B到A信息包的传送时间d为:

d = ((t4 - t1) - (t3 - t2))/2

假定B机相对于A机的时间误差是c,则有下列等式:

t2 = t1 + c + d
t4 = t3 - c + d

从以上三个等式可以解出B机的时间误差c为:

c = ((t2 - t1) + (t3 - t4)) / 2

如果一时没有转过来,可以自己在纸上画个图,在细细地琢磨一下,应该没有问题。

2、简单网络时间协议SNTPv4(Simple Network Time Protocol version 4)

  SNTPv4由NTP改编而来,主要支持同步网络计算机时钟机制。SNTPv4没有改变NTP规范和原有实现过程,它是对NTP的进一步改进,支持以一种简单、无状态远程过程调用模式执行精确而可靠的操作,这类似于UDP/TIME协议。

3、SNTP(NTP)的协议结构

123
0 1 2 3 4 5 6 7 8 9 0 1 2 3 45 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|LI | VN |Mode| Stratum| Poll| Precision |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|RootDelay|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|RootDispersion|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|ReferenceIdentifier|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
||
|Reference Timestamp(64)|
||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
||
|Originate Timestamp(64)|
||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
||
|Receive Timestamp(64)|
||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
||
|Transmit Timestamp(64)|
||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Key Identifier (optional)(32)|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
||
||
|Message Digest (optional)(128)|
||
||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

有对协议感兴趣的读者,可以在下面地址下载SNTP协议进行深入的研究。

http://blog.hengch.com/specification/sntp.pdf

4、SNTP的实际实现

说起来一大堆,但实现起来其实并不像说的那么复杂。

根据SNTP协议第5节《SNTP ClientOperations》的说明,如果采用unicast模式,其目的就是为了获得准确时间的话,向服务器发送的请求包中,除了第一个字节以外,其他的SNTP字段都可以设为0,这正好与我们的目的相符,下面我们给出实现本机与时间服务器同步的源程序。

还有两个细节要说明,一是NTP实用的端口号是123,二是NTP的header中的字符顺序是big-endian,也就是NetworkByteOrder(详见另一篇博文:《在DOS下进行网络编程(下)》中的描述),而我们本机的字符顺序是little-endian,所以在收到服务器的回应后要注意转换。

为方便说明,源程序前面加了行号。

001 #include<stdio.h>
002 #include<dos.h>
003 #include<sys/socket.h>
004 #include<arpa/inet.h>

005 #defineSNTP_PORT 123
006 #define SNTP_SERVER"210.72.145.44" // China
007 //#defineSNTP_SERVER"192.43.244.18" // NIST :sometimes ok
008 //#defineSNTP_SERVER"192.5.41.40" // U.S NavalObservatory : ok
009 //#defineSNTP_SERVER "128.102.16.2"
010 #defineSNTP_EPOCH 86400U * (365U* 70U + 17U)
011 #defineSNTP_8HOUR 3600U * 8U

012 struct Sntp_Header {
013 unsigned char LiVnMode;
014 unsigned char Stratum;
015 unsigned char Poll;
016 unsigned char Precision;
017 long int RootDelay;
018 long int RootDispersion;
019 char RefID[4];
020 long int RefTimeInt;
021 long int RefTimeFraction;
022 long int OriTimeInt;
如何与时间服务器进行时间同步 系统时间同步服务器
023 long int OriTimeFraction;
024 long int RecvTimeInt;
025 long int RecvTimeFraction;
026 long int TranTimeInt;
027 long int TranTimeFraction;
028 };

029 int main() {
030 int retValue;
031 fd_set readfds;
032 // Structure of SNTP
033 struct Sntp_Header sntpHeader;
034 struct Sntp_Header sntpHeader1;
035 struct Sntp_Header *p;
036 char *p1;
037 // vars of network
038 int sendSock;
039 struct sockaddr_in toAddr;
040 int addrLen;
041 char *pBuf;
042 long int OriTimeInt;
043 long int DestTimeInt;
044 long int difference;
045 unsigned char tempChar;

046 struct timeval tv;

047 struct date dateNow;
048 struct time timeNow;

049 sendSock = socket(AF_INET,SOCK_DGRAM, 0);

050 if (sendSock < 0){
051 printf("nsendSocketCreation Fail!");
052 return -1;
053 }

054toAddr.sin_family = AF_INET;
055toAddr.sin_port =htons(SNTP_PORT);
056 toAddr.sin_addr.s_addr =inet_addr(SNTP_SERVER);
057bzero(&(toAddr.sin_zero), 8);
058 addrLen = sizeof(struct sockaddr);

059 bzero(&sntpHeader,sizeof(struct Sntp_Header));
060 sntpHeader.LiVnMode = 0x1b;

061 OriTimeInt = time(0) + SNTP_EPOCH -SNTP_8HOUR;
062 retValue = sendto(sendSock,&sntpHeader, sizeof(struct Sntp_Header), 0,
(struct sockaddr *)&toAddr, addrLen);
063 printf("nSend %d chars.",retValue);
064 p1 = (char*)&sntpHeader;
065 pBuf = (char*)&sntpHeader1;

066printf("ntSent...tttttReceived...");
067 for (int j = 0; j < 12;j++) {
068FD_ZERO(&readfds);
069 FD_SET(sendSock,&readfds);
070 tv.tv_sec = 10;
071 tv.tv_usec = 0;
072 select(sendSock + 1,&readfds, NULL, NULL, &tv);
073 if (FD_ISSET(sendSock,&readfds)) {
074 retValue =recvfrom(sendSock,
&pBuf[j * 4],
4,
0,
(struct sockaddr *)&toAddr,
&addrLen);
075 } else{
076 printf("nDidnot Get information from time server");
077 return-1;
078 }

079 if (retValue<= 0 ) {
080printf("nReceiving Fail");
081 return-1;
082 }
083 printf("n");
084 for (int i = 0; i< retValue; i++) {
085printf("t%02x", (unsigned char)p1[i + j * 4]);
086 }
087 printf("t");
088 for (int i = 0; i< retValue; i++) {
089printf("t%02x", (unsigned char)pBuf[i + j * 4]);
090 }
091 }

092 for (int j = 4; j< 12; j++) {
093 tempChar = *(pBuf + j *4);
094 *(pBuf + j * 4) = *(pBuf +j * 4 + 3);
095 *(pBuf + j * 4 + 3) =tempChar;
096 tempChar = *(pBuf + j * 4+ 1);
097 *(pBuf + j * 4 + 1) =*(pBuf + j * 4 + 2);
098 *(pBuf + j * 4 + 2) =tempChar;
099 }

100 p = (struct Sntp_Header *)pBuf;

101 DestTimeInt = time((time_t *)NULL)+ SNTP_EPOCH - SNTP_8HOUR;
102 printf("nLocal TimeStamp = %lu",DestTimeInt);
103 printf("tRefTimeInt = %lu",p->RefTimeInt);
104 printf("nOriTimeInt = %lu",OriTimeInt);
105 printf("tRecvTimeInt = %lu",p->RecvTimeInt);
106 printf("nTranTimeInt = %lu",p->TranTimeInt);
107 difference =(p->RecvTimeInt - OriTimeInt) +(p->TranTimeInt - DestTimeInt);
108 difference = difference / 2;
109 printf("tdifference = %ld",difference);

110 tv.tv_usec = 0;
111 tv.tv_sec = time(0) +difference;
112getdate(&dateNow);
113gettime(&timeNow);
114 printf("nDate and Time Beforeadjusting : %04d-%02d-%02d%02d:%02d:%02d",
dateNow.da_year, dateNow.da_mon, dateNow.da_day,
timeNow.ti_hour, timeNow.ti_min, timeNow.ti_sec);
115 retValue =settimeofday(&tv);
116 if (retValue == 0){
117 printf("nSetting Timeok!");
118 } else{
119 printf("nSetting TimeFail!");
120 }
121getdate(&dateNow);
122gettime(&timeNow);
123 printf("nDate and Time afteradjusting : %04d-%02d-%02d%02d:%02d:%02dn",
dateNow.da_year, dateNow.da_mon, dateNow.da_day,
timeNow.ti_hour, timeNow.ti_min, timeNow.ti_sec);
124 return 0;
125 }

下面就程序的某些部分作一些说明。

至此,程序解释完毕,该程序在DOS6.22,DJGPPv2,WATT-32下编译通过并运行良好。

下一篇文章计划写如何在DOS对AC'97的声卡进行编程,会举一个实例,敬请期待。

  

爱华网本文地址 » http://www.413yy.cn/a/25101013/146467.html

更多阅读

洛克王国稀有宠物获取地点与时间 洛克王国刷绝版宠物

洛克王国稀有宠物获取地点与时间——简介洛克王国历史悠久,地质资源丰富,气候温和。这个王国有许多古老的传说,还有一些很隐秘的古老魔法,没有人能够找到它们。洛克族统治着这片大陆,他们团结友爱,同心协力,努力建设着他们梦想中的家园。

Win7如何建立还原点进行系统还原? 怎么还原win7系统

Win7如何建立还原点进行系统还原?——简介我们有时容易使我们的电脑系统遭到损坏或者出现某些错误设置,此时我们可以把系统还原到损坏前的系统。这就需要通过系统还原来进行系统保护,撤销到系统更改前的状态。系统还原会撤销以前的系统

火车票取票方式与时间规定 网上买票怎么取票火车

火车票取票方式与时间规定——简介取票也是有时间固定的,大家一定要不要错过取票的时间。下面为大家介绍取票时间规定,及取票的几种方式。火车票取票方式与时间规定——取票必备有效身份证件、订单号火车票取票方式与时间规定——取

十二时辰与时间对照表 十二时辰养生对照表

十二时辰与时间对照表,十二经络时辰表(转)2010-09-19 16:15:02古代每个时辰都是两个小时,用“子丑寅卯辰巳午未申酉戌亥”12个字代替,子时是凌晨23:00-1:00,以此推算,申时是15:00-17:00点.【子时】夜半,又名子夜、中夜:十二时辰的第一个时辰

声明:《如何与时间服务器进行时间同步 系统时间同步服务器》为网友性与晚餐分享!如侵犯到您的合法权益请联系我们删除