赞
踩
https://www.cnblogs.com/zy791976083/p/9779421.html
一、时间类型及常用函数
(1)时间类型
本地时间(locale time)
格林威治时间(Greenwich Mean Time GMT)
世界标准时间 (Universal Time Coordinated UTC)
GMT、UTC时间,都是以秒数为单位计数,而不是真实世界中的年月日,时分秒时间。
这个时间是从1970年01月01日 0:00:00起到现在经过的秒数,例如运行下面代码:
- #include <time.h>
- #include <stdio.h>
-
- int main()
- {
- time_t timep; //用来存储从1970年到现在经过了多少秒
- time(&timep); //获取time_t类型的当前时间
- printf("%ld\n", timep); printf("%s", ctime(&timep));
- return 0;
- }
得到:1539332642
通过函数ctime()将其转换为真实世界时间:Fri Oct 12 16:30:01 2018
(2)常用时间函数举例
因为时区不同的关系,不同函数取得的时间会相差8个小时(北京处于东八区)。简单举例:
获得UTC时间:time()、asctime()、gmtime()... ...
获得经时区转换后的时间:ctime()、localtime()... ...
- #include <time.h>
- #include <stdio.h>
-
- int main()
- {
- time_t timep;
- time(&timep);
- printf("%ld\n", timep);
- printf("北京时间:%s", ctime(&timep));
- printf("UTC时间:%s", asctime(gmtime(&timep)));
- return 0;
- }
更多与时间相关的内容可参考这个博客:https://blog.csdn.net/ybhjx/article/details/69374354
(3)UTC时间转换成秒,再转换成当前时间
- #include <time.h>
- #include <stdio.h>
- /*struct tm {
- int tm_sec; /* 秒 – 取值区间为[0,59] */
- int tm_min; /* 分 - 取值区间为[0,59] */
- int tm_hour; /* 时 - 取值区间为[0,23] */
- int tm_mday; /* 一个月中的日期 - 取值区间为[1,31] */
- int tm_mon; /* 月份(从一月开始,0代表一月) - 取值区间为[0,11] */
- int tm_year; /* 年份,其值等于实际年份减去1900 */
- int tm_wday; /* 星期 – 取值区间为[0,6],其中0代表星期天,1代表星期一 */
- int tm_yday; /* 从每年1月1日开始的天数– 取值区间[0,365],其中0代表1月1日 */
- int tm_isdst; /* 夏令时标识符,夏令时tm_isdst为正;不实行夏令时tm_isdst为0 */
- };*/
- typedef struct RTSPUTCTime
- {
- int year;
- int mon;
- int day;
- int hour;
- int min;
- int second;
- } RTSPUTCTime;
-
- time_t utc2seconds(RTSPUTCTime *utc)
- {
- struct tm tm_time;
-
- memset(&tm_time, 0, sizeof(tm_time));
- tm_time.tm_year = utc->year - 1900;
- tm_time.tm_mon = utc->mon;
- tm_time.tm_mday = utc->day;
- tm_time.tm_hour = utc->hour;
- tm_time.tm_min = utc->min;
- tm_time.tm_sec = utc->second;
- return mktime(&tm_time);
- }
-
- int main(){ struct tm *tm_now; RTSPUTCTime utc = {2019,3,15,9,30,15}; // 给定一个UTC时间 time_t seektime = utc2seconds(&utc); // 将UTC时间转化为秒 tm_now = localtime(&seektime); // 将秒转化为当前时间
- printf("tm_now =%d-%d-%d %d:%d:%d \n",tm_now->tm_year+1900, tm_now->tm_mon, tm_now->tm_mday, tm_now->tm_hour, tm_now->tm_min, tm_now->tm_sec);}
二、实现NTP同步功能
了解了时间概念后,要做的就比较明确了
(1)发送NTP请求报文,从一个NTP服务器获取到时间
(2)更新系统时间
这里可以参考博客:简单的NTP客户端-C语言实现,讲解详细,提供的代码稍作修改编译就通过了,很好用。
关于我修改的地方:
(1)从一个NTP服务器获取到时间
我选择的NTP服务器IP地址:119.28.183.184(百度可以查到国家授时中心IP等)
(2)更新系统时间
代码里的settimeofday(&tv, NULL)函数,是需要root权限的。怎么在普通用户下实现NTP同步呢,
①命令加程序:
先登录root用户设置程序的UID,#chmod u+s 文件名。
然后在更新系统时间部分添加如下代码
- uid_t uid = getuid();
- if (setuid(0)) {
- return -1;
- }
- //...
- if (setuid(uid)) { //恢复uid
- }
通过上面步骤则该用户不管在普通用户还是在root用户下都能获取root权限。
②不使用命令的情况,完整代码如下:
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <time.h>
- #include<iostream>
- #include <unistd.h>
- #include <sys/select.h>
- #include<sys/time.h>
- #include <sys/socket.h>
- #include <arpa/inet.h>
- #include <netdb.h>
- #include <errno.h>
- #include <endian.h>
-
- #define VERSION_3 3
- #define VERSION_4 4
-
- #define MODE_CLIENT 3
- #define MODE_SERVER 4
-
- #define NTP_LI 0
- #define NTP_VN VERSION_3
- #define NTP_MODE MODE_CLIENT
- #define NTP_STRATUM 0
- #define NTP_POLL 4
- #define NTP_PRECISION -6
-
- #define NTP_HLEN 48
-
- #define NTP_PORT 123
- #define NTP_SERVER "182.92.12.11"
-
- #define TIMEOUT 10
-
- #define BUFSIZE 1500
-
- #define JAN_1970 0x83aa7e80
-
- #define NTP_CONV_FRAC32(x) (uint64_t) ((x) * ((uint64_t)1<<32))
- #define NTP_REVE_FRAC32(x) ((double) ((double) (x) / ((uint64_t)1<<32)))
-
- #define NTP_CONV_FRAC16(x) (uint32_t) ((x) * ((uint32_t)1<<16))
- #define NTP_REVE_FRAC16(x) ((double)((double) (x) / ((uint32_t)1<<16)))
-
-
- #define USEC2FRAC(x) ((uint32_t) NTP_CONV_FRAC32( (x) / 1000000.0 ))
- #define FRAC2USEC(x) ((uint32_t) NTP_REVE_FRAC32( (x) * 1000000.0 ))
-
-
- #define NTP_LFIXED2DOUBLE(x) ((double) ( ntohl(((struct l_fixedpt *) (x))->intpart) - JAN_1970 + FRAC2USEC(ntohl(((struct l_fixedpt *) (x))->fracpart)) / 1000000.0 ))
-
- using namespace std;
- struct s_fixedpt {
- uint16_t intpart;
- uint16_t fracpart;
- };
-
- struct l_fixedpt {
- uint32_t intpart;
- uint32_t fracpart;
- };
-
-
- struct ntphdr {
- #if __BYTE_ORDER == __BID_ENDIAN
- unsigned int ntp_li:2;
- unsigned int ntp_vn:3;
- unsigned int ntp_mode:3;
- #endif
- #if __BYTE_ORDER == __LITTLE_ENDIAN
- unsigned int ntp_mode:3;
- unsigned int ntp_vn:3;
- unsigned int ntp_li:2;
- #endif
- uint8_t ntp_stratum;
- uint8_t ntp_poll;
- int8_t ntp_precision;
- struct s_fixedpt ntp_rtdelay;
- struct s_fixedpt ntp_rtdispersion;
- uint32_t ntp_refid;
- struct l_fixedpt ntp_refts;
- struct l_fixedpt ntp_orits;
- struct l_fixedpt ntp_recvts;
- struct l_fixedpt ntp_transts;
- };
-
-
- in_addr_t inet_host(const char *host)
- {
- in_addr_t saddr;
- struct hostent *hostent;
-
- if ((saddr = inet_addr(host)) == INADDR_NONE) {
- if ((hostent = gethostbyname(host)) == NULL)
- return INADDR_NONE;
-
- memmove(&saddr, hostent->h_addr, hostent->h_length);
- }
-
- return saddr;
- }
-
-
- int get_ntp_packet(void *buf, size_t *size) //构建并发送NTP请求报文
- {
- struct ntphdr *ntp;
- struct timeval tv;
-
-
- if (!size || *size<NTP_HLEN)
- return -1;
-
- memset(buf, 0, *size);
-
- ntp = (struct ntphdr *) buf;
- ntp->ntp_li = NTP_LI;
- ntp->ntp_vn = NTP_VN;
- ntp->ntp_mode = NTP_MODE;
- ntp->ntp_stratum = NTP_STRATUM;
- ntp->ntp_poll = NTP_POLL;
- ntp->ntp_precision = NTP_PRECISION;
-
- gettimeofday(&tv, NULL); //把目前的时间用tv 结构体返回
- ntp->ntp_transts.intpart = htonl(tv.tv_sec + JAN_1970);
- ntp->ntp_transts.fracpart = htonl(USEC2FRAC(tv.tv_usec));
-
- *size = NTP_HLEN;
-
- return 0;
- }
-
-
-
- double get_rrt(const struct ntphdr *ntp, const struct timeval *recvtv) //往返时延
- {
- double t1, t2, t3, t4;
-
- t1 = NTP_LFIXED2DOUBLE(&ntp->ntp_orits);
- t2 = NTP_LFIXED2DOUBLE(&ntp->ntp_recvts);
- t3 = NTP_LFIXED2DOUBLE(&ntp->ntp_transts);
- t4 = recvtv->tv_sec + recvtv->tv_usec / 1000000.0;
-
- return (t4 - t1) - (t3 - t2);
- }
-
-
- double get_offset(const struct ntphdr *ntp, const struct timeval *recvtv) //偏移量
- {
- double t1, t2, t3, t4;
-
- t1 = NTP_LFIXED2DOUBLE(&ntp->ntp_orits);
- t2 = NTP_LFIXED2DOUBLE(&ntp->ntp_recvts);
- t3 = NTP_LFIXED2DOUBLE(&ntp->ntp_transts);
- t4 = recvtv->tv_sec + recvtv->tv_usec / 1000000.0;
-
- return ((t2 - t1) + (t3 - t4)) / 2;
- }
-
-
-
-
- int main(int argc, char *argv[])
- {
- char dateBuf[64] = {0};
- char cmd[128] = {0};
- tm* local;
- char buf[BUFSIZE];
- size_t nbytes;
- int sockfd, maxfd1;
- struct sockaddr_in servaddr;
- fd_set readfds;
- struct timeval timeout, recvtv, tv;
- double offset;
-
- // if (argc != 2) {
- // usage();
- // exit(-1);
-
-
- servaddr.sin_family = AF_INET;
- servaddr.sin_port = htons(NTP_PORT);
- servaddr.sin_addr.s_addr = inet_host("119.28.183.184");
-
- if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
- perror("socket error");
- exit(-1);
- }
-
- if (connect(sockfd, (struct sockaddr *) &servaddr, sizeof(struct sockaddr)) != 0) {
- perror("connect error");
- exit(-1);
- }
- nbytes = BUFSIZE;
- if (get_ntp_packet(buf, &nbytes) != 0) {
- fprintf(stderr, "construct ntp request error \n");
- exit(-1);
- }
- send(sockfd, buf, nbytes, 0);
-
-
- FD_ZERO(&readfds);
- FD_SET(sockfd, &readfds);
- maxfd1 = sockfd + 1;
-
-
- timeout.tv_sec = TIMEOUT;
- timeout.tv_usec = 0;
-
- if (select(maxfd1, &readfds, NULL, NULL, &timeout) > 0) {
- if (FD_ISSET(sockfd, &readfds))
- {
- if ((nbytes = recv(sockfd, buf, BUFSIZE, 0)) < 0)
- {
- perror("recv error");
- exit(-1);
- }
-
- //计算C/S时间偏移量
- gettimeofday(&recvtv, NULL);
- offset = get_offset((struct ntphdr *) buf, &recvtv);
- 更新系统时间
-
- gettimeofday(&tv, NULL);
-
- tv.tv_sec += (int) offset +28800;
- tv.tv_usec += offset - (int) offset;
-
- local = localtime((time_t *) &tv.tv_sec);
- strftime(dateBuf, 64, "%Y-%m-%d %H:%M:%S", local);
- sprintf(cmd, "system busybox date -s \"%s\"", dateBuf);
-
- printf("%s \n", ctime((time_t *) &tv.tv_sec));
-
-
- }
- }
-
- close(sockfd);
-
- return 0;
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。