关于类NTP服务器的一段代码,用于同步平台和nvr的时间。望大家不吝赐教: - #include <stdio.h>
#include <stdlib.h> #include <WinSock2.h> #include <time.h> #include <stdio.h> #define int8 char #define uint8 unsigned char #define uint32 unsigned int #define ulong32 unsigned long #define long32 long #define int32 int #define long64 long long #pragma comment( lib, "ws2_32.lib") #define NTPPORT 9966 typedef struct NTPPACKET { uint8 li_vn_mode; uint8 stratum; uint8 poll; uint8 precision; ulong32 root_delay; ulong32 root_dispersion; int8 ref_id[4]; ulong32 reftimestamphigh; ulong32 reftimestamplow; ulong32 oritimestamphigh; ulong32 oritimestamplow; ulong32 recvtimestamphigh; ulong32 recvtimestamplow; ulong32 trantimestamphigh; ulong32 trantimestamplow; }NTPPacket; NTPPacket recvPack,sendPack; //定义为long64,解决32位数的符号位问题 long64 recvtimestamphigh = 0,timeSpace = 0x83aa7e80U; //3600s*24h*(365days*70years+17days) void CombineNTPPackage() { memset(&sendPack,0,sizeof(sendPack)); sendPack.li_vn_mode=0x1b; recvtimestamphigh= timeSpace+time(NULL); //设置发往客户端的时间戳, 0x83aa7e80U 是1900年到1970总共的秒数,由于time(time_t *time)只能算出1970到今天的总共时间(秒) NTP时间同步报文中包含的时间是格林威治时间,是从1900年开始计算的秒数 sendPack.recvtimestamphigh = htonl(recvtimestamphigh); } int main() { WSADATA wsaData; WORD sockVer = MAKEWORD(2, 2); WSAStartup(sockVer, &wsaData); int32 sockfd = -1; struct sockaddr_in servaddr, clientAddr; if((sockfd=socket(AF_INET,SOCK_DGRAM,0))<0){ perror("create socket error!\n"); return -1; } memset(&servaddr, 0,sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(NTPPORT); if(bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1) { perror("bind error"); return -1; } int ret = -1; int len = sizeof(clientAddr); time_t sTime,eTime; while(1) { ret = recvfrom(sockfd, (char*)&recvPack, sizeof(recvPack), 0, (struct sockaddr *)&clientAddr,&len ); if(ret>0){ sTime = time(NULL); CombineNTPPackage(); eTime = time(NULL); sendPack.trantimestamphigh = timeSpace+eTime+eTime-sTime; if(sendto(sockfd,(char*)&sendPack,sizeof(sendPack),0,(struct sockaddr *)&clientAddr,sizeof(struct sockaddr))<0){ perror("sendto data error!\n"); } }else { perror("recvfrom socket error!\n"); if(0 == ret) break; Sleep(100); continue; } Sleep(10000); } closesocket(sockfd); WSACleanup( ); }
注:1,NTP协议算时间差: 客户机跟服务器的时间差=((T2-T1)+(T3-T4))>>1 T1是客户端的时间戳 :recvPack.oritimestamphigh; T2是服务器自身的时间戳 :sendPack.recvtimestamphigh T3是服务器处理过后发往客户端的时间戳 :newpack.trantimestamphigh T4是客户端收到数据的时候的时间戳:finaltimes= time(NULL)+timeSpace - difftime=((sendPack.recvtimestamphigh-recvPack.oritimestamphigh)+(newpack.trantimestamphigh-finaltimes))>>1;
2,客户端算延时: - delaytime=((sendPack.recvtimestamphigh-recvPack.oritimestamphigh)-(sendPack.trantimestamphigh-finaltimes))>>1;
3,客户端算真正时间的时间戳: - struct timeval tv1 tv1.tv_sec=time(NULL)+difftime+delaytime;
tv1.tv_usec=0;
|