⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sntp.c

📁 网络时间同步协议的实现
💻 C
字号:
/*说明:     1)  本程序读取配置文件/etc/ntp.conf中的server段所示的时间服务器,如tick.stdtime.gov.tw等;    2)  将这些服务器名转换为IP地址.加入服务器列表中.服务器列表最多能加入MAX_TIME_SERVER个时间服务器.    3)  从服务器列表中选取一个比较精确的时间服务器,使本机同其同步.    4)  主进程调用register_serv()函数载入时间服务器的IP地址,然后调用sntp_start()函数起动sntp客户端.    5)  sntp客户端收到发往本进程的UDP包,判定是合法时间服务器所发的包后,作一些比较处理并修改时间.    6)  本进程起动的时间间隔为UPDATEPERIOD秒,超时时间定义为UPDATETIMEOUT秒,分别定义为30*60和10;    7)  有关ntp/sntp的数据结构在sntp.h中定义;*/#include "sntp.h"static intis_better (struct sntp_srv_s *newer, struct sntp_srv_s *old){  time_t last_time, diff;  if (!memcmp (&newer->addr, &old->addr, sizeof (struct sockaddr)))    return 1;  if (newer->stratum < old->stratum)    return 1;  if (old->timestamp != 0xffffffff)    {      last_time = TIME_NTP_TO_LOCAL (old->timestamp);      diff = time (NULL) - last_time;      if (diff > 600)	return 1;      return 0;    }  return 1;}intisInServerList (struct sockaddr_in *pserver_addr,		struct sockaddr_in *sntp_server_list,		unsigned int sntp_num_servers){  int i;  for (i = 0; i < sntp_num_servers; i++)    {      if (memcmp	  (&(pserver_addr->sin_addr), &(sntp_server_list[i].sin_addr),	   sizeof (struct in_addr)) == 0)	{	  if (pserver_addr->sin_port == htons(TIME_PORT))	    return 1;	}    }  return 0;}voidsntp_start (struct sockaddr_in *server_list, unsigned int num_servers){  if (num_servers == 0)    return;  struct sockaddr_in *sntp_servers = server_list;  unsigned int sntp_num_servers = num_servers;  time_t NextTimeUpdate = 0;  int fd;  int ret;  NTP_PACKET ntp_pkt;  struct sntp_srv_s new_srv;  struct sntp_srv_s best_srv;  int mode;  int len;  time_t new_time, current_time, diff;  fd_set readfds;  int n;  int i;  struct timeval timeout;  struct timeval *ptimeout = NULL;  struct sockaddr_in *preply_addr =    (struct sockaddr_in *) malloc (sizeof (struct sockaddr_in));  memset (&best_srv, 0xff, sizeof (best_srv));  fd = socket (AF_INET, SOCK_DGRAM, 0);  if (fd <= 0)    {      perror ("Failed to open socket");      return;    }  n = fd;  while (1)    {      FD_ZERO (&readfds);      FD_SET (fd, &readfds);      timeout.tv_sec = SNTP_WAITPERIOD;      timeout.tv_usec = 0;      ptimeout = &timeout;      if (NextTimeUpdate != 0)	{	  current_time = time (NULL);	  if (current_time < NextTimeUpdate)	    {	      timeout.tv_sec =		(SNTP_WAITPERIOD >		 (NextTimeUpdate - current_time) ? (NextTimeUpdate -						    current_time) :		 SNTP_WAITPERIOD);	    }	  else	    NextTimeUpdate = 0;	}      if (NextTimeUpdate == 0 && (sntp_num_servers > 0))	{	  memset (&ntp_pkt, 0, sizeof (ntp_pkt));	  ntp_pkt.Control =	    NTP_LI_NOLEAP |	    NTP_MODE_SET (NTP_MODE_CLIENT) | NTP_VERSION_SET (3);	  for (i = 0; i < sntp_num_servers; i++)	    {	      ntp_pkt.TransmitTimestamp.Seconds =		htonl (TIME_LOCAL_TO_NTP (time (NULL)));	      sendto (fd, &ntp_pkt, sizeof (ntp_pkt), 0,		      (struct sockaddr *) &(sntp_servers[i]),		      sizeof (struct sockaddr_in));	      NextTimeUpdate = time (NULL) + SNTP_WAITPERIOD;	    }	  ret = select (n + 1, &readfds, NULL, NULL, ptimeout);	  if (ret <= 0)	    {	      printf ("timeout or error occur\n");	      sleep (1);	      continue;	    }	  len = sizeof (struct sockaddr);	  if (FD_ISSET (fd, &readfds))	    {	      ret =		recvfrom (fd, &ntp_pkt, sizeof (ntp_pkt), 0,			  (struct sockaddr *) preply_addr, &len);	      if (!isInServerList		  (preply_addr, sntp_servers, sntp_num_servers))		continue;	    }	  if (ret < NTP_PACKET_MINLEN)	    {	      perror ("receive size too small");	      continue;	    }	  new_srv.version = NTP_VERSION_GET (&ntp_pkt);	  new_srv.stratum = ntp_pkt.Stratum;	  new_srv.timestamp = ntohl (ntp_pkt.TransmitTimestamp.Seconds);	  mode = NTP_MODE_GET (&ntp_pkt);	  if (new_srv.version < 3 || new_srv.version > 4)	    {	      continue;	    }	  if (mode != NTP_MODE_BROADCAST && mode != NTP_MODE_SERVER)	    continue;	  if (is_better (&new_srv, &best_srv))	    {	      best_srv = new_srv;	      new_time = TIME_NTP_TO_LOCAL (best_srv.timestamp);	      current_time = time (NULL);	      diff = current_time - new_time;	      if (diff < 0)		diff = -diff;	      if (diff > 2)		stime (&new_time);	    }          sleep (SNTP_UPDATEPERIOD);	  NextTimeUpdate = time (NULL);	}    }}intregister_serv (int j, char *server_name, struct sockaddr_in *server_list){  int i;  struct hostent *hp;  char *pname;  pname = server_name;  while ((*pname != ' ') && (*pname != '\t') && (*pname != '\n'))    pname++;  (*pname) = 0;  printf ("the server_name=%s,and the len=%d\n", server_name,	  strlen (server_name));  for (i = 0; i < 3; i++)    {      if (!(hp = gethostbyname (server_name)))	continue;      else	break;    }  if (hp == NULL)    return 0;  memcpy (&(server_list[j].sin_addr), hp->h_addr, 4);  server_list[j].sin_port = htons (TIME_PORT);  server_list[j].sin_family = AF_INET;  return 1;}intmain (){  int ifork;  if ((ifork = fork ()) < 0)    {      printf (">>can't fork\n");      exit (-1);    }  else if (ifork > 0)    {      exit (0);    }  struct sockaddr_in time_server_list[MAX_SNTP_SERVER];  FILE *fp;  fp = fopen ("/etc/ntp.conf", "r");  if (fp <= 0)    {      printf (" 配置文件不存在,程序不能执行\n");      exit (0);    }  char linebuf[MAXLINE];  char servname[100];  int i = 0;  char *pname;  while (fgets (linebuf, MAXLINE, fp) != NULL)    {      if ((strncmp (linebuf, "server", 6) == 0))	{	  pname = linebuf;	  pname += 7;	  while ((*pname) == ' ')	    pname++;	  if (strncmp (pname, "127.", 4) == 0)	    continue;	  if (i > MAX_SNTP_SERVER)	    break;	  if (register_serv (i, pname, time_server_list))	    {	      printf ("the time server %s is registered\n", pname);	      i++;	    }	  else	    {	      printf ("the time server %s register failed\n", pname);	    }	}      else	continue;    }  fclose (fp);  sntp_start ((struct sockaddr_in *) time_server_list, i--);  exit (0);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -