单播SNTP客户端
一、功能实现
以NTP服务器为基准,同步网内计算机或嵌入式设备的时间。
二、协议原理
协议:
客户端向NTP服务器发送请求数据包,NTP服务器回应一个数据包。
分别记录客户端发送请求包时的时刻t1和接收到回应包的时刻t4,服务器回应的数据包内包含了服务器接收到请求包的时刻t2和服务器发送回应包的时刻t3。
t4-t1表示整个消息传递过程所需要的时间;
t3-t2表示消息传递过程在服务器停留的时间;
(t4-t1)-(t3-t2)是来回路上消耗的时间,如果来回传输所用的时间一样,那么,单程的时间为:
t = ( (t4 - t1) - (t3 - t2) )/2;
假定客户端相对于服务器的时间误差是dis,则有下列等式:
t2 = t1 + dis + t;
t4 = t3 - dis + t;
则:dis = (( t2 - t1 ) + ( t3 - t4 )) / 2;
根据此差值重新设置时间即可。
说明:
服务器发返回的时间是以1900年为基准计算的,而linux是以1970年为基准的,所以需要用到一个常数做转化:
#define JAN_1970 2208988800UL /* 1970 - 1900 in seconds */
在计算与服务器的差值时会用到此值。
三、代码实现
ntp.h
- #ifndef __NTP_H
- #define __NTP_H
- #define JAN_1970 2208988800UL /* 1970 - 1900 in seconds */
- #define NTP_SERVER_NAME "10.13.0.21" //my windows 7 ntp server
- #define NTP_PORT 123
- /* some ntp server
- time-a.nist.gov
- time-b.nist.gov
- time-a.timefreq.bldrdoc.gov
- time-b.timefreq.bldrdoc.gov
- time-c.timefreq.bldrdoc.gov
- utcnist.colorado.edu
- ntp.tuxfamily.net
- time-nw.nist.gov
- nist1.datum.com
- nist1-ny.glassey.com
- nist1.aol-ca.truetime.com
- ntp2.belbone.be
- ntp.doubleukay.com
- ntp0.cs.mu.OZ.AU
- time.apple.com
- 0.pool.ntp.org
- 1.pool.ntp.org
- 2.pool.ntp.org
- 2.europe.pool.ntp.org
- 3.europe.pool.ntp.org
- 1.north-america.pool.ntp.org
- 2.north-america.pool.ntp.org
- 0.oceania.pool.ntp.org
- 1.oceania.pool.ntp.org
- 0.au.pool.ntp.org
- 3.au.pool.ntp.org
- */
- typedef struct
- {
- unsigned char LiVnMode;
- unsigned char Stratum;
- unsigned char Poll;
- unsigned char Precision;
- long int RootDelay;
- long int RootDispersion;
- char RefID[4];
- long int RefTimeInt;
- long int RefTimeFraction;
- long int OriTimeInt;
- long int OriTimeFraction;
- long int RecvTimeInt;
- long int RecvTimeFraction;
- long int TranTimeInt;
- long int TranTimeFraction;
- }STNP_Header;
- int SYNC_Time(void);
- #endif
- #include <stdio.h>
- #include <unistd.h>
- #include <string.h>
- #include <time.h>
- #include <sys/time.h>
- #include <netinet/in.h>
- #include <sys/socket.h>
- #include <arpa/inet.h>
- #include <netdb.h>
- #include "sntp.h"
- int gethostIPbyname(char *name)
- {
- struct hostent *host=NULL;
- struct in_addr *addr=NULL;
- host = gethostbyname (name);
- if(host->h_addr == NULL)
- return -1;
- addr = (struct in_addr*)host->h_addr;
- return addr->s_addr;
- }
- int GetNTPTime(STNP_Header *H_SNTP)
- {
- int sockfd=0;
- struct sockaddr_in server;
- bzero((void*)H_SNTP, sizeof(STNP_Header));
- H_SNTP->LiVnMode = 0x1b;
- server.sin_family = AF_INET;
- server.sin_addr.s_addr = gethostIPbyname(NTP_SERVER_NAME);
- server.sin_port = htons(NTP_PORT);
- if(-1 == (int)server.sin_addr.s_addr)
- return -1;
- sockfd = socket(AF_INET, SOCK_DGRAM, 0);
- if(sockfd<0)
- {
- perror("sockfd");
- return -1;
- }
- if(sendto(sockfd, (void*)H_SNTP, sizeof(STNP_Header), 0, (struct sockaddr*)&server, sizeof(server))<0)
- {
- perror("sendto");
- return -1;
- }
- fd_set r;
- FD_ZERO(&r);
- FD_SET(sockfd, &r);
- struct timeval timeout;
- timeout.tv_sec = 5;
- timeout.tv_usec = 0;
- if(1 != select(sockfd+1, &r, NULL, NULL, &timeout))
- return -1;
- if(recv(sockfd, (void*)H_SNTP, sizeof(STNP_Header), 0)<0)
- return -1;
- close(sockfd);
- return 0;
- }
- int SYNC_Time(void)
- {
- STNP_Header HeaderSNTP;
- time_t t1,t2,t3,t4,dis;
- time(&t1);
- t1+=JAN_1970;
- printf("sync time from %s\n", NTP_SERVER_NAME);
- if(GetNTPTime(&HeaderSNTP)<0)
- return -1;
- time(&t4);
- t4+=JAN_1970;
- t2 = ntohl(HeaderSNTP.RecvTimeInt);
- t3 = ntohl(HeaderSNTP.TranTimeInt);
- dis = ( (t2-t1)+(t3-t4) )/2;
- if(dis<=0)
- printf("local time is faster then server %d seconds\n", (int)-dis);
- else
- printf("local time is slower then server %d seconds\n", (int)dis);
- struct timeval tv;
- gettimeofday (&tv, 0);
- tv.tv_sec+=dis;
- printf("%s", ctime(&tv.tv_sec));
- settimeofday (&tv, NULL);
- return 0;
- }
- #include <stdio.h>
- #include "sntp.h"
- int main(void)
- {
- if(SYNC_Time()<0)
- printf("sync time Failed!\n");
- printf("sync time Succeed!\n");
- return 0;
- }
文章来源: blog.csdn.net,作者:悟空胆好小,版权归原作者所有,如需转载,请联系作者。
原文链接:blog.csdn.net/xushx_bigbear/article/details/45054801
- 点赞
- 收藏
- 关注作者
评论(0)