虽然说原理上并不难,但是过程中却也遇到了些问题。重要的是,做完这个实验之后,搞清了一些平时并不太注意的东西。
另外,只计算了整数部分,小数部分没有计算。校正后的时间跟标准时间误差不超过一秒。
接下来复习并总结一下前一阵学过的内容,并且准备拟定下一个阶段的计划。
//colinluan 090613
//GMT时间:格林威治时间,国际标准时间,中国位于东八区,时间为GMT+8
//UTC时间: 通用协调时间,可以认为跟GMT是一个概念。
//时间戳:NTP服务器上的时间戳为从1900年1月1日0时0分开始到至今的秒数(UTC时间)
// 而PC机上的时间戳为1970年1月1日0时0分到至今的秒数(程序中的time(NULL)返回的是UTC时间)
// 所以,要对PC机的时间戳与服务器时间戳计算时,需在PC机的时间戳基础上加上1900-1970的秒数 3600s*24h*(365days*70years+17days)
// 客户机跟服务器的时间差=((T2-T1)+(T3-T4))>>1
// 传输延时=((T2-T1)-(T3-T4))>>1 (假设来跟去的传输延时是一样的)
// T1 请求离开客户端的时间戳
// T2 请求到达服务器的时间戳(由服务器返回)
// T3 从服务器返回的时间戳(由服务器返回)
// T4 返回数据包到达客户端的时间戳
// 客户端(请求) 服务器
// T1 ---------------------------------> T2
// (返回)
// T4 <--------------------------------- T3
// 在计算时由于会碰到32位数的符号位问题,索性用64位数进行计算。
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <netinet/in.h>
-
#include <arpa/inet.h>
-
//#include <netdb.h>
-
#include <sys/socket.h>
-
#include <sys/types.h>
-
#include <sys/time.h>
-
#include <unistd.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
-
-
#define debug
-
-
//3600s*24h*(365days*70years+17days)
-
#define From00to70 0x83aa7e80U
-
-
#define NTPSVR1 "132.163.4.102" //USA
-
#define NTPSVR2 "132.163.135.132" //USA
-
#define NTPSVR3 "192.53.103.103" //Germany
-
-
#define NTPPORT 123
-
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 ntppack,newpack;
-
-
//定义为long64,解决32位数的符号位问题
-
long64 firsttimestamp,finaltimestamp;
-
long64 diftime,delaytime;
-
-
void NTP_Init()
-
{
-
bzero(&ntppack,sizeof(ntppack));
-
ntppack.li_vn_mode=0x1b;//0|(3<<2)|(3<<5);
-
//获取初始时间戳T1
-
firsttimestamp=From00to70+time(NULL);//-8*3600;
-
ntppack.oritimestamphigh=htonl(firsttimestamp);
-
}
-
int main()
-
{
-
// ulong32 clienttime;
-
// ulong32 diftime,firsttimestamp,finaltimestamp;
-
fd_set inset1;
-
int32 sockfd;
-
struct timeval tv,tv1;
-
struct timezone tz;
-
struct sockaddr_in addr;
-
// printf("%d,%d,%d\n",&ntppack.li_vn_mode,&ntppack.stratum,&ntppack.poll);
-
// printf("%d %ld\n",sizeof(NTPPacket),sizeof(ntppack));
-
-
// printf("%ld\n",time(NULL));
-
-
if((sockfd=socket(AF_INET,SOCK_DGRAM,0))<0)
-
{
-
perror("create socket error!\n");
-
exit(1);
-
}
-
-
addr.sin_family=AF_INET; //IPV4协议
-
addr.sin_port =htons(NTPPORT); //NTP专用的123端口
-
addr.sin_addr.s_addr=inet_addr(NTPSVR1); //校时服务器
-
bzero(&(addr.sin_zero),8); //清零
-
-
//wait 5s
-
tv.tv_sec=10; //select等待时间为10S
-
tv.tv_usec=0;
-
-
FD_ZERO(&inset1);
-
FD_SET(sockfd,&inset1);
-
-
NTP_Init();
-
//发送数据请求包
-
sendto(sockfd,&ntppack,sizeof(ntppack),0,(struct sockaddr *)&addr,sizeof(struct sockaddr));
-
//select巡视
-
if(select(sockfd+1,&inset1,NULL,NULL,&tv)<0)
-
{
-
perror("select error!\n");
-
exit(1);
-
}
-
else
-
{
-
//printf("OK\n");
-
if(FD_ISSET(sockfd,&inset1))
-
{
-
// printf("OK\n");
-
if(recv(sockfd,&newpack,sizeof(newpack),0)<0) //接收数据在newpack中。
-
{
-
perror("recv error!\n");
-
exit(1);
-
}
-
}
-
}
-
//到达客户机时间戳T4
-
finaltimestamp=time(NULL)+From00to70;//-8*3600;
-
-
//将网络上传送的大端数据改为小端形式。
-
newpack.root_delay= ntohl(newpack.root_delay);
-
newpack.root_dispersion= ntohl(newpack.root_dispersion);
-
newpack.reftimestamphigh=ntohl(newpack.reftimestamphigh);
-
newpack.reftimestamplow= ntohl(newpack.reftimestamplow);
-
newpack.oritimestamphigh= ntohl(newpack.oritimestamphigh);
-
newpack.oritimestamplow= ntohl(newpack.oritimestamplow);
-
newpack.recvtimestamphigh= ntohl(newpack.recvtimestamphigh);
-
newpack.recvtimestamplow= ntohl(newpack.recvtimestamplow);
-
newpack.trantimestamphigh= ntohl(newpack.trantimestamphigh);
-
newpack.trantimestamplow= ntohl(newpack.trantimestamplow);
-
-
//求出客户机跟服务器的时间差=((T2-T1)+(T3-T4))/2
-
diftime=((newpack.recvtimestamphigh-firsttimestamp)+(newpack.trantimestamphigh-finaltimestamp))>>1;
-
//求出延时
-
delaytime=((newpack.recvtimestamphigh-firsttimestamp)-(newpack.trantimestamphigh-finaltimestamp))>>1;
-
//diftime=(5-9)>>1;
-
-
//求出真正时间的时间戳
-
tv1.tv_sec=time(NULL)+diftime+delaytime;
-
tv1.tv_usec=0;
-
//tz.
-
-
#ifdef debug
-
printf("\n\ndebug information ...\n\n");
-
printf("time(NULL) is %ld\n",time(NULL));
-
printf("different time is %ld\n",diftime);
-
printf("delaytime is %ld\n",delaytime);
-
printf("time(NULL)+diftime+delaytime=%ld\n",time(NULL)+diftime+delaytime);
-
printf("tv1.tv_sec is %ld\n\n", tv1.tv_sec);
-
#endif
-
-
settimeofday(&tv1,NULL);
-
//diftime=diftime-From00to70;
-
-
#ifdef debug
-
//printf("different time is %ld\n",diftime);
-
printf("delay time is %ld\n",delaytime);
-
//printf("firsttimestamp is %x\n",time(NULL));
-
printf("newpack.tran is %ld\n",newpack.trantimestamphigh);
-
printf("newpack.recv is %ld\n",newpack.recvtimestamphigh);
-
printf("firsttimestamp is %ld\n",firsttimestamp);
-
printf("finaltimestamp is %ld\n",finaltimestamp);
-
printf("newpack.recv-firsttimestamp is %ld\n",newpack.recvtimestamphigh-firsttimestamp);
-
printf("newpack.tran-finaltimestamp is %ld\n",newpack.trantimestamphigh-finaltimestamp);
-
printf("(recv-first)+(ftran-final) is %ld\n",(newpack.recvtimestamphigh-firsttimestamp)+(newpack.trantimestamphigh-finaltimestamp));
-
printf("((recv-first)+(ftran-final))>>1 is %ld\n",((newpack.recvtimestamphigh-firsttimestamp)+(newpack.trantimestamphigh-finaltimestamp))>>1);
-
printf("different time is %ld\n\n",diftime);
-
printf("sizeof(long long) is:%d\n",sizeof(long long));
-
printf("Current time is...\n");
-
system("date");
-
#endif
-
}
注:原文代码59行和117行错误已修改,目前可以编译通过并成功运行。
转自:
阅读(2631) | 评论(0) | 转发(0) |