Linux NTP协议

网络时间协议( network time protocol,简称ntp)是用来在整个网络内发布精确时间的tcp/ip 协议,其本身的传输基于udp。其基本原理如下: 
  
上图所示的是 ntp 基本工作原理,路由器gwa 和gwb 通过网络相连,它们都有自己独立的系统时钟,    要实现各自系统时钟的自动同步,作如下假设:
1 在 gwa 和gwb 的系统时钟同步之前, gwa 的时钟设定为10:00:00am,gwb 的时钟设定为11:00:00am。
2 以 gwb 为ntp 时间服务器,即gwa 将使自己的时钟与gwb 的时钟同步。
3 数据包在 gwa 和gwb 之间单向传输所需要的时间为1 秒。
    系统时钟同步的工作过程如下:
1 gwa 发送一个 ntp 消息包给gwb,该消息包带有它离开gwa 时的时间戳,该时间戳为10:00:00am(t1)。
2 当此 ntp 消息包到达gwb 时,gwb 加上自己的时间戳,该时间戳为11:00:01am(t2)。
3 当此 ntp 消息包离开gwb 时,gwb 再加上自己的时间戳,该时间戳为11:00:02am(t3)。
4 当 gwa 接收到该响应消息包时,加上一个新的时间戳,该时间戳为10:00:03am(t4)。
至此, gwa 已经拥有足够的信息,来计算两个重要的参数:
5 ntp 消息来回一个周期的时延 delay=(t4-t1)-(t3-t2)。
6 gwa 相对 gwb 的时间差offset=((t2-t1)+(t3-t4))/2。
这样, gwa 就能够根据这些信息,来设定自己的时钟,使之与gwb 的时钟同步。这只是ntp 工作原理的一个粗略描述,在rfc1305 规范中,ntp 使用复杂的算法,来确保时钟同步的精确性。
根据网络结构以及路由器在网络中的位置, ntp 有六种工作模式,其中前两种模式也称单播模式。
1 设置远程服务器为本地时间服务器,此时本地路由器工作在 client 模式。在这种工作模式下,只能是本地客户机同步到远程服务器,而远程服务器不会同步到本地客户机;
2 设置远程服务器作为本地路由器的对等体,本地运行在 symmetric active 模式(即主动模式)在。这种配置下,本地服务器能同步到远程服务器(被动模式),远程服务器也能同步到本地服务器。如果双方都有参考时钟,以层数小的为准;
3 设置本地路由器的一个接口发送 ntp 的广播消息包,此时,本地路由器工作在广播服务器模式;
4 设置本地路由器的一个接口接收 ntp 的广播信息包,此时,本地路由器工作在广播客户模式;
5 设置本地路由器的一个接口发送 ntp 组播消息包,本地路由器运行在组播服务器模式;

6 设置本地路由器的一个接口接收ntp 组播消息包,本地路由器运行在组播客户模式。

 

Linux下通过NTP协议实现服务器时间同步(C实现)

#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 tim 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
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值