NTP协议

柔情只为你懂 2022-03-17 09:24 314阅读 0赞

网络时间协议,英文名称:Network Time Protocol(NTP

linux C/C++实现同步NTP时间

简单的NTP客户端-C语言实现

NTP协议简介

关于下面的C++代码,我是基于博客园席纳霍霍的代码进行修改的。他的代码在我的系统里运行时间不对。非常感谢上面3位作者无私奉献。

C++ 代码:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <time.h>
  5. #include<iostream>
  6. #include <unistd.h>
  7. #include <sys/select.h>
  8. #include<sys/time.h>
  9. #include <sys/socket.h>
  10. #include <arpa/inet.h>
  11. #include <netdb.h>
  12. #include <errno.h>
  13. #include <endian.h>
  14. #define VERSION_3 3
  15. #define VERSION_4 4
  16. #define MODE_CLIENT 3
  17. #define MODE_SERVER 4
  18. #define NTP_LI 0
  19. #define NTP_VN VERSION_3
  20. #define NTP_MODE MODE_CLIENT
  21. #define NTP_STRATUM 0
  22. #define NTP_POLL 4
  23. #define NTP_PRECISION -6
  24. #define NTP_HLEN 48
  25. #define NTP_PORT 123
  26. #define NTP_SERVER "182.92.12.11"
  27. #define TIMEOUT 10
  28. #define BUFSIZE 1500
  29. #define JAN_1970 0x83aa7e80
  30. #define NTP_CONV_FRAC32(x) (uint64_t) ((x) * ((uint64_t)1<<32))
  31. #define NTP_REVE_FRAC32(x) ((double) ((double) (x) / ((uint64_t)1<<32)))
  32. #define NTP_CONV_FRAC16(x) (uint32_t) ((x) * ((uint32_t)1<<16))
  33. #define NTP_REVE_FRAC16(x) ((double)((double) (x) / ((uint32_t)1<<16)))
  34. #define USEC2FRAC(x) ((uint32_t) NTP_CONV_FRAC32( (x) / 1000000.0 ))
  35. #define FRAC2USEC(x) ((uint32_t) NTP_REVE_FRAC32( (x) * 1000000.0 ))
  36. #define NTP_LFIXED2DOUBLE(x) ((double) ( ntohl(((struct l_fixedpt *) (x))->intpart) - JAN_1970 + FRAC2USEC(ntohl(((struct l_fixedpt *) (x))->fracpart)) / 1000000.0 ))
  37. using namespace std;
  38. struct s_fixedpt {
  39. uint16_t intpart;
  40. uint16_t fracpart;
  41. };
  42. struct l_fixedpt {
  43. uint32_t intpart;
  44. uint32_t fracpart;
  45. };
  46. struct ntphdr {
  47. #if __BYTE_ORDER == __BID_ENDIAN
  48. unsigned int ntp_li:2;
  49. unsigned int ntp_vn:3;
  50. unsigned int ntp_mode:3;
  51. #endif
  52. #if __BYTE_ORDER == __LITTLE_ENDIAN
  53. unsigned int ntp_mode:3;
  54. unsigned int ntp_vn:3;
  55. unsigned int ntp_li:2;
  56. #endif
  57. uint8_t ntp_stratum;
  58. uint8_t ntp_poll;
  59. int8_t ntp_precision;
  60. struct s_fixedpt ntp_rtdelay;
  61. struct s_fixedpt ntp_rtdispersion;
  62. uint32_t ntp_refid;
  63. struct l_fixedpt ntp_refts;
  64. struct l_fixedpt ntp_orits;
  65. struct l_fixedpt ntp_recvts;
  66. struct l_fixedpt ntp_transts;
  67. };
  68. in_addr_t inet_host(const char *host)
  69. {
  70. in_addr_t saddr;
  71. struct hostent *hostent;
  72. if ((saddr = inet_addr(host)) == INADDR_NONE) {
  73. if ((hostent = gethostbyname(host)) == NULL)
  74. return INADDR_NONE;
  75. memmove(&saddr, hostent->h_addr, hostent->h_length);
  76. }
  77. return saddr;
  78. }
  79. int get_ntp_packet(void *buf, size_t *size) //构建并发送NTP请求报文
  80. {
  81. struct ntphdr *ntp;
  82. struct timeval tv;
  83. if (!size || *size<NTP_HLEN)
  84. return -1;
  85. memset(buf, 0, *size);
  86. ntp = (struct ntphdr *) buf;
  87. ntp->ntp_li = NTP_LI;
  88. ntp->ntp_vn = NTP_VN;
  89. ntp->ntp_mode = NTP_MODE;
  90. ntp->ntp_stratum = NTP_STRATUM;
  91. ntp->ntp_poll = NTP_POLL;
  92. ntp->ntp_precision = NTP_PRECISION;
  93. gettimeofday(&tv, NULL); //把目前的时间用tv 结构体返回
  94. ntp->ntp_transts.intpart = htonl(tv.tv_sec + JAN_1970);
  95. ntp->ntp_transts.fracpart = htonl(USEC2FRAC(tv.tv_usec));
  96. *size = NTP_HLEN;
  97. return 0;
  98. }
  99. double get_rrt(const struct ntphdr *ntp, const struct timeval *recvtv) //往返时延
  100. {
  101. double t1, t2, t3, t4;
  102. t1 = NTP_LFIXED2DOUBLE(&ntp->ntp_orits);
  103. t2 = NTP_LFIXED2DOUBLE(&ntp->ntp_recvts);
  104. t3 = NTP_LFIXED2DOUBLE(&ntp->ntp_transts);
  105. t4 = recvtv->tv_sec + recvtv->tv_usec / 1000000.0;
  106. return (t4 - t1) - (t3 - t2);
  107. }
  108. double get_offset(const struct ntphdr *ntp, const struct timeval *recvtv) //偏移量
  109. {
  110. double t1, t2, t3, t4;
  111. t1 = NTP_LFIXED2DOUBLE(&ntp->ntp_orits);
  112. t2 = NTP_LFIXED2DOUBLE(&ntp->ntp_recvts);
  113. t3 = NTP_LFIXED2DOUBLE(&ntp->ntp_transts);
  114. t4 = recvtv->tv_sec + recvtv->tv_usec / 1000000.0;
  115. return ((t2 - t1) + (t3 - t4)) / 2;
  116. }
  117. int main(int argc, char *argv[])
  118. {
  119. char dateBuf[64] = {0};
  120. char cmd[128] = {0};
  121. tm* local;
  122. char buf[BUFSIZE];
  123. size_t nbytes;
  124. int sockfd, maxfd1;
  125. struct sockaddr_in servaddr;
  126. fd_set readfds;
  127. struct timeval timeout, recvtv, tv;
  128. double offset;
  129. // if (argc != 2) {
  130. // usage();
  131. // exit(-1);
  132. servaddr.sin_family = AF_INET;
  133. servaddr.sin_port = htons(NTP_PORT);
  134. servaddr.sin_addr.s_addr = inet_host("119.28.183.184");
  135. if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
  136. perror("socket error");
  137. exit(-1);
  138. }
  139. if (connect(sockfd, (struct sockaddr *) &servaddr, sizeof(struct sockaddr)) != 0) {
  140. perror("connect error");
  141. exit(-1);
  142. }
  143. nbytes = BUFSIZE;
  144. if (get_ntp_packet(buf, &nbytes) != 0) {
  145. fprintf(stderr, "construct ntp request error \n");
  146. exit(-1);
  147. }
  148. send(sockfd, buf, nbytes, 0);
  149. FD_ZERO(&readfds);
  150. FD_SET(sockfd, &readfds);
  151. maxfd1 = sockfd + 1;
  152. timeout.tv_sec = TIMEOUT;
  153. timeout.tv_usec = 0;
  154. if (select(maxfd1, &readfds, NULL, NULL, &timeout) > 0) {
  155. if (FD_ISSET(sockfd, &readfds))
  156. {
  157. if ((nbytes = recv(sockfd, buf, BUFSIZE, 0)) < 0)
  158. {
  159. perror("recv error");
  160. exit(-1);
  161. }
  162. //计算C/S时间偏移量
  163. gettimeofday(&recvtv, NULL);
  164. offset = get_offset((struct ntphdr *) buf, &recvtv);
  165. 更新系统时间
  166. gettimeofday(&tv, NULL);
  167. tv.tv_sec += (int) offset ;//+28800;//alen
  168. tv.tv_usec += offset - (int) offset;
  169. local = localtime((time_t *) &tv.tv_sec);
  170. strftime(dateBuf, 64, "%Y-%m-%d %H:%M:%S", local);
  171. sprintf(cmd, "system busybox date -s \"%s\"", dateBuf);
  172. cout << cmd <<endl;
  173. //printf("%s\n",cmd); //alen
  174. printf("%s \n", ctime((time_t *) &tv.tv_sec));
  175. }
  176. }
  177. close(sockfd);
  178. return 0;
  179. }

C代码:

  1. /* ntpclient.c */
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <time.h>
  6. #include <unistd.h>
  7. #include <sys/select.h>
  8. #include <sys/socket.h>
  9. #include <arpa/inet.h>
  10. #include <netdb.h>
  11. #include <errno.h>
  12. #include <endian.h>
  13. #define VERSION_3 3
  14. #define VERSION_4 4
  15. #define MODE_CLIENT 3
  16. #define MODE_SERVER 4
  17. #define NTP_LI 0
  18. #define NTP_VN VERSION_3
  19. #define NTP_MODE MODE_CLIENT
  20. #define NTP_STRATUM 0
  21. #define NTP_POLL 4
  22. #define NTP_PRECISION -6
  23. #define NTP_HLEN 48
  24. #define NTP_PORT 123
  25. #define NTP_SERVER "182.92.12.11"
  26. #define TIMEOUT 10
  27. #define BUFSIZE 1500
  28. #define JAN_1970 0x83aa7e80
  29. #define NTP_CONV_FRAC32(x) (uint64_t) ((x) * ((uint64_t)1<<32))
  30. #define NTP_REVE_FRAC32(x) ((double) ((double) (x) / ((uint64_t)1<<32)))
  31. #define NTP_CONV_FRAC16(x) (uint32_t) ((x) * ((uint32_t)1<<16))
  32. #define NTP_REVE_FRAC16(x) ((double)((double) (x) / ((uint32_t)1<<16)))
  33. #define USEC2FRAC(x) ((uint32_t) NTP_CONV_FRAC32( (x) / 1000000.0 ))
  34. #define FRAC2USEC(x) ((uint32_t) NTP_REVE_FRAC32( (x) * 1000000.0 ))
  35. #define NTP_LFIXED2DOUBLE(x) ((double) ( ntohl(((struct l_fixedpt *) (x))->intpart) - JAN_1970 + FRAC2USEC(ntohl(((struct l_fixedpt *) (x))->fracpart)) / 1000000.0 ))
  36. struct s_fixedpt {
  37. uint16_t intpart;
  38. uint16_t fracpart;
  39. };
  40. struct l_fixedpt {
  41. uint32_t intpart;
  42. uint32_t fracpart;
  43. };
  44. struct ntphdr {
  45. #if __BYTE_ORDER == __BID_ENDIAN
  46. unsigned int ntp_li:2;
  47. unsigned int ntp_vn:3;
  48. unsigned int ntp_mode:3;
  49. #endif
  50. #if __BYTE_ORDER == __LITTLE_ENDIAN
  51. unsigned int ntp_mode:3;
  52. unsigned int ntp_vn:3;
  53. unsigned int ntp_li:2;
  54. #endif
  55. uint8_t ntp_stratum;
  56. uint8_t ntp_poll;
  57. int8_t ntp_precision;
  58. struct s_fixedpt ntp_rtdelay;
  59. struct s_fixedpt ntp_rtdispersion;
  60. uint32_t ntp_refid;
  61. struct l_fixedpt ntp_refts;
  62. struct l_fixedpt ntp_orits;
  63. struct l_fixedpt ntp_recvts;
  64. struct l_fixedpt ntp_transts;
  65. };
  66. in_addr_t inet_host(const char *host)
  67. {
  68. in_addr_t saddr;
  69. struct hostent *hostent;
  70. if ((saddr = inet_addr(host)) == INADDR_NONE) {
  71. if ((hostent = gethostbyname(host)) == NULL)
  72. return INADDR_NONE;
  73. memmove(&saddr, hostent->h_addr, hostent->h_length);
  74. }
  75. return saddr;
  76. }
  77. int get_ntp_packet(void *buf, size_t *size)
  78. {
  79. struct ntphdr *ntp;
  80. struct timeval tv;
  81. if (!size || *size<NTP_HLEN)
  82. return -1;
  83. memset(buf, 0, *size);
  84. ntp = (struct ntphdr *) buf;
  85. ntp->ntp_li = NTP_LI;
  86. ntp->ntp_vn = NTP_VN;
  87. ntp->ntp_mode = NTP_MODE;
  88. ntp->ntp_stratum = NTP_STRATUM;
  89. ntp->ntp_poll = NTP_POLL;
  90. ntp->ntp_precision = NTP_PRECISION;
  91. gettimeofday(&tv, NULL);
  92. ntp->ntp_transts.intpart = htonl(tv.tv_sec + JAN_1970);
  93. ntp->ntp_transts.fracpart = htonl(USEC2FRAC(tv.tv_usec));
  94. *size = NTP_HLEN;
  95. return 0;
  96. }
  97. void print_ntp(struct ntphdr *ntp)
  98. {
  99. time_t time;
  100. printf("LI:\t%d \n", ntp->ntp_li);
  101. printf("VN:\t%d \n", ntp->ntp_vn);
  102. printf("Mode:\t%d \n", ntp->ntp_mode);
  103. printf("Stratum:\t%d \n", ntp->ntp_stratum);
  104. printf("Poll:\t%d \n", ntp->ntp_poll);
  105. printf("precision:\t%d \n", ntp->ntp_precision);
  106. printf("Route delay:\t %lf \n",
  107. ntohs(ntp->ntp_rtdelay.intpart) + NTP_REVE_FRAC16(ntohs(ntp->ntp_rtdelay.fracpart)));
  108. printf("Route Dispersion:\t%lf \n",
  109. ntohs(ntp->ntp_rtdispersion.intpart) + NTP_REVE_FRAC16(ntohs(ntp->ntp_rtdispersion.fracpart)));
  110. printf("Referencd ID:\t %d \n", ntohl(ntp->ntp_refid));
  111. time = ntohl(ntp->ntp_refts.intpart) - JAN_1970;
  112. printf("Reference:\t%d %ld %s \n",
  113. ntohl(ntp->ntp_refts.intpart) - JAN_1970,
  114. FRAC2USEC(ntohl(ntp->ntp_refts.fracpart)),
  115. ctime(&time));
  116. time = ntohl(ntp->ntp_orits.intpart) - JAN_1970;
  117. printf("Originate:\t%d %d frac=%ld (%s) \n",
  118. ntohl(ntp->ntp_orits.intpart) - JAN_1970,
  119. FRAC2USEC(ntohl(ntp->ntp_orits.fracpart)),
  120. ntohl(ntp->ntp_orits.fracpart),
  121. ctime(&time) );
  122. time = ntohl(ntp->ntp_recvts.intpart) - JAN_1970;
  123. printf("Receive:\t%d %d (%s) \n",
  124. ntohl(ntp->ntp_recvts.intpart) - JAN_1970,
  125. FRAC2USEC(ntohl(ntp->ntp_recvts.fracpart)),
  126. ctime(&time) );
  127. time = ntohl(ntp->ntp_transts.intpart) - JAN_1970;
  128. printf("Transmit:\t%d %d (%s) \n",
  129. ntohl(ntp->ntp_transts.intpart) - JAN_1970,
  130. FRAC2USEC(ntohl(ntp->ntp_transts.fracpart)),
  131. ctime(&time) );
  132. }
  133. double get_rrt(const struct ntphdr *ntp, const struct timeval *recvtv)
  134. {
  135. double t1, t2, t3, t4;
  136. t1 = NTP_LFIXED2DOUBLE(&ntp->ntp_orits);
  137. t2 = NTP_LFIXED2DOUBLE(&ntp->ntp_recvts);
  138. t3 = NTP_LFIXED2DOUBLE(&ntp->ntp_transts);
  139. t4 = recvtv->tv_sec + recvtv->tv_usec / 1000000.0;
  140. return (t4 - t1) - (t3 - t2);
  141. }
  142. double get_offset(const struct ntphdr *ntp, const struct timeval *recvtv)
  143. {
  144. double t1, t2, t3, t4;
  145. t1 = NTP_LFIXED2DOUBLE(&ntp->ntp_orits);
  146. t2 = NTP_LFIXED2DOUBLE(&ntp->ntp_recvts);
  147. t3 = NTP_LFIXED2DOUBLE(&ntp->ntp_transts);
  148. t4 = recvtv->tv_sec + recvtv->tv_usec / 1000000.0;
  149. return ((t2 - t1) + (t3 - t4)) / 2;
  150. }
  151. void usage(void)
  152. {
  153. fprintf(stderr,
  154. "Usage : ntpclient"
  155. " destination"
  156. "\n"
  157. );
  158. }
  159. int main(int argc, char *argv[])
  160. {
  161. char buf[BUFSIZE];
  162. size_t nbytes;
  163. int sockfd, maxfd1;
  164. struct sockaddr_in servaddr;
  165. fd_set readfds;
  166. struct timeval timeout, recvtv, tv;
  167. double offset;
  168. if (argc != 2) {
  169. usage();
  170. exit(-1);
  171. }
  172. servaddr.sin_family = AF_INET;
  173. servaddr.sin_port = htons(NTP_PORT);
  174. servaddr.sin_addr.s_addr = inet_host(argv[1]);
  175. if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
  176. perror("socket error");
  177. exit(-1);
  178. }
  179. if (connect(sockfd, (struct sockaddr *) &servaddr, sizeof(struct sockaddr)) != 0) {
  180. perror("connect error");
  181. exit(-1);
  182. }
  183. nbytes = BUFSIZE;
  184. if (get_ntp_packet(buf, &nbytes) != 0) {
  185. fprintf(stderr, "construct ntp request error \n");
  186. exit(-1);
  187. }
  188. send(sockfd, buf, nbytes, 0);
  189. FD_ZERO(&readfds);
  190. FD_SET(sockfd, &readfds);
  191. maxfd1 = sockfd + 1;
  192. timeout.tv_sec = TIMEOUT;
  193. timeout.tv_usec = 0;
  194. if (select(maxfd1, &readfds, NULL, NULL, &timeout) > 0) {
  195. if (FD_ISSET(sockfd, &readfds)) {
  196. if ((nbytes = recv(sockfd, buf, BUFSIZE, 0)) < 0) {
  197. perror("recv error");
  198. exit(-1);
  199. }
  200. gettimeofday(&recvtv, NULL);
  201. offset = get_offset((struct ntphdr *) buf, &recvtv);
  202. gettimeofday(&tv, NULL);
  203. tv.tv_sec += (int) offset;
  204. tv.tv_usec += offset - (int) offset;
  205. if (settimeofday(&tv, NULL) != 0) {
  206. perror("settimeofday error");
  207. exit(-1);
  208. }
  209. printf("%s \n", ctime((time_t *) &tv.tv_sec));
  210. }
  211. }
  212. close(sockfd);
  213. return 0;
  214. }

发表评论

表情:
评论列表 (有 0 条评论,314人围观)

还没有评论,来说两句吧...

相关阅读

    相关 NTP协议

    NTP(Network Time Protocol)是一种用于在计算机网络中同步各个节点时间的协议。它通过将一台计算机的时钟同步到另一台计算机的时钟来实现时间同步。NTP协议是