最近公司比较空,花了一些时间学习了一下linux的应用编程,并且在今天下午完成了最后一章socket的实验。内容就是实现ntp协议,使本机的时间与ntp服务器同步。
虽然说原理上并不难,但是过程中却也遇到了些问题。重要的是,做完这个实验之后,搞清了一些平时并不太注意的东西。
另外,只计算了整数部分,小数部分没有计算。校正后的时间跟标准时间误差不超过一秒。
接下来复习并总结一下前一阵学过的内容,并且准备拟定下一个阶段的计划。
//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
}
文章评论(0条评论)
登录后参与讨论