NTP同步时间

参考:

NTP协议-蒲公英云

#ifndef __NTP_UPDATE_TIME_H__
#define __NTP_UPDATE_TIME_H__
#include <types.h>
#include <logBaseWork.h>
#include <miscOperate.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.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 1
#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))
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;
};
class ntpOptSyncTimeClass
{
public:
    static 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;
    }
    static 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;
    }
    static 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);
    }
    static 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;
    }
    static int getNtpTimeNow(std::string ipaddr, u16 ntpPort, time_t &ntpTime)
    {
        // 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;
        servaddr.sin_family = AF_INET;
        servaddr.sin_port = htons(ntpPort);
        servaddr.sin_addr.s_addr = inet_host(ipaddr.c_str());
        if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
        {
            logwerr("open err");
            return -1;
        }
        if (connect(sockfd, (struct sockaddr *)&servaddr, sizeof(struct sockaddr)) != 0)
        {
            logwerr("connect error");
            goto outFuncPoint;
        }
        nbytes = BUFSIZE;
        if (get_ntp_packet(buf, &nbytes) != 0)
        {
            fprintf(stderr, "construct ntp request error \n");
            goto outFuncPoint;
        }
        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)
                {
                    logwerr("recv error");
                    goto outFuncPoint;
                }
                //计算C/S时间偏移量
                gettimeofday(&recvtv, NULL);
                offset = get_offset((struct ntphdr *)buf, &recvtv);
                gettimeofday(&tv, NULL);
                tv.tv_sec += (int)offset; //+28800;//alen
                tv.tv_usec += offset - (int)offset;
                ntpTime = tv.tv_sec;
                return 0;
            }
        }
    outFuncPoint:
        close(sockfd);
        return -2;
    }

    //reference ntp server:https://blog.csdn.net/weixin_42284074/article/details/123173016
    // std::string testNtpHostList[] = 
    // {
    //     "ntp.ntsc.ac.cn",//中国国家授时中心
    //     // "cn.ntp.org.cn",//中国授时
    //     //阿里云NTP时间源服务器
    //     "ntp1.aliyun.com",
    //     "ntp2.aliyun.com",
    //     "ntp3.aliyun.com",
    //     "ntp4.aliyun.com",
    //     "ntp5.aliyun.com",
    //     "ntp6.aliyun.com",
    //     "ntp7.aliyun.com",
    //     //国内一些大学NTP时间源服务器
    //     // "s1a.time.edu.cn",//   北京邮电大学
    //     // "s1b.time.edu.cn",//   清华大学
    //     // "s1c.time.edu.cn",//   北京大学
    //     // "s1d.time.edu.cn",//   东南大学
    //     // "s1e.time.edu.cn",//   清华大学
    //     // "s2a.time.edu.cn",//   清华大学
    //     // "s2b.time.edu.cn",//   清华大学
    //     // "s2c.time.edu.cn",//   北京邮电大学
    //     // "s2d.time.edu.cn",//   西南地区网络中心
    //     // "s2e.time.edu.cn",//   西北地区网络中心
    //     // "s2f.time.edu.cn",//   东北地区网络中心
    //     // "s2g.time.edu.cn",//   华东南地区网络中心
    //     // "s2h.time.edu.cn",//   四川大学网络管理中心
    //     // "s2j.time.edu.cn",//   大连理工大学网络中心
    //     // "s2k.time.edu.cn",// CERNET桂林主节点
    //     // "s2m.time.edu.cn",//   北京大学
    // };
    // int main()
    // {
    //     for(int i = 0; i < (int)ARRAY_LEN(testNtpHostList); i++)
    //     {
    //         logwdbg("-------->update :%s", testNtpHostList[i].c_str());
    //         ntpOptSyncTimeClass::updateNtpTime(testNtpHostList[i], 123);
    //     }
    //     return 0;
    // }
    static void updateNtpTime(std::string ipaddr, u16 ntpPort)
    {
        time_t ntpGetTime, timeNow;
        if (getNtpTimeNow(ipaddr, ntpPort, ntpGetTime) == 0)
        {
            timeNow = time(NULL);
            tm *loct = localtime(&ntpGetTime);
            logwdbg("%d-%d-%d %d:%d:%d", loct->tm_year + 1900, loct->tm_mon + 1, loct->tm_mday, loct->tm_hour, loct->tm_min, loct->tm_sec);
            if (abs(ntpGetTime - timeNow) < 30)
            {
                return;
            }
            struct timeval tmptval = {ntpGetTime, 0};
            settimeofday(&tmptval, NULL);
            miscOperateClass::sysPro("hwclock -w -u");
        }
        else
        {
            logwwrn("up ntp fail: %s", ipaddr.c_str());
        }
        
    }
};
#endif

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值