文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Linux时间校准(ntpdate及NTP客户端代码校准示例)

2023-08-30 12:59

关注

背景

机器每次机启后时间就会出现异常,因为机器无法访问外网,只能访问局域网的ntp服务,所以需要保证局域网内部有ntp服务,如何安装ntp服务,参考Ubuntu20.04 Ntp服务安装及验证

网络时间协议Network Time Protocol(NTP) 是一种确保时钟保持准确的方法。如果可以访问互联网,只需安装ntp的客户端软件到互联网上的公共ntp服务器自动修正时间即可

一、系统时间和硬件时间

Linux在默认情况下,系统时间和硬件时间并不会自动同步。而是以异步的方式运行,互不干扰。其中硬件时间的运行,是靠Bios电池来维持,而系统时间,是用CPU 时钟来维持的。

在系统开机的时候,会自动从Bios中取得硬件时间,设置为系统时间。

1.1 date命令

用来查看和设置系统时间

date   #查看系统当前时间sudo date -s "2023-03-18 11:16:10"  #修改系统时间为 "xxxx-xx-xx xx:xx:xx"===============================================================================nvidia@nvidia-desktop:~$ dateВт мар 18 11:16:27 +08 2023nvidia@nvidia-desktop:~$nvidia@nvidia-desktop:~$nvidia@nvidia-desktop:~$ sudo date -s "2023-03-18 11:16:10"[sudo] password for nvidia:Вт мар 18 11:16:10 +08 2023nvidia@nvidia-desktop:~$

硬件时间的设置,可以用hwclock

1.2 hwclock 命令

查看当前硬件时间

注意:hwclock 所有命令需要使用root 权限

nvidia@nvidia-desktop:~$ hwclockhwclock: Cannot access the Hardware Clock via any known method.hwclock: Use the --debug option to see the details of our search for an access method.nvidia@nvidia-desktop:~$nvidia@nvidia-desktop:~$nvidia@nvidia-desktop:~$ sudo hwclock2023-03-21 11:18:49.607690+0800nvidia@nvidia-desktop:~$

将系统时间同步到硬件时间

hwclock -w

将硬件时间同步到系统时间

hwclock -s

二、不同机器间时间同步

为了避免主机时间因为长期运作下所导致的时间偏差,进行时间同步(synchronize)的工作是非常必要的。Linux系统下,一般使用ntp服务器来同步不同机器的时间。一台机器,可以同时是ntp服务器和ntp客户机。

2.1 ntpdate命令实现

ntpdate 安装:

yum install ntpdate -y   # Centos系统======================================sudo apt install ntpdate  # Ubuntu系统

时间同步

sudo ntpdate -u cn.pool.ntp.org18 Mar 18:25:22 ntpdate[18673]: adjust time server 84.16.73.33 offset 0.015941 sec

使用ntpdate 只是强制将系统时间设置为ntp服务器时间,如果cpu tick有问题,时间还是会不准。所以,一般配合cron命令,来进行定期同步设置。比如,在crontab中添加:

sudo crontab -e0 12 * * * * /usr/sbin/ntpdate 192.168.10.110

上述命令的意思是:每天的12点整,从192.168.10.110 ntp服务器同步一次时间(前提是 192.168.10.110有ntp服务)。

2.2 Ntp客户端代码实现

本质上还是创建socket连接去获取ntp服务的时间与本地时间比较,不一致修改本机时间即可。

NtpClient.h

//// Created by lwang on 2023-03-18.//#ifndef NTP_CLIENT_H#define NTP_CLIENT_H#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std;#define NTP_LI          0#define NTP_VERSION_NUM 3#define NTP_MODE_CLIENT 3#define NTP_MODE_SERVER 4#define NTP_STRATUM 0#define NTP_POLL    4#define NTP_PRECISION -6#define NTP_MIN_LEN   48#define NTP_SERVER_PORT 123#define NTP_SERVER_ADDR "119.28.183.184"#define TIMEOUT 2#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 NtpClient {public:    NtpClient();    virtual ~NtpClient();    void        GetNtpTime(std::string &ntpTime);    in_addr_t   HostTransfer(const char *host);    int         PaddingNtpPackage(void *buf, size_t *size);    double      GetOffset(const struct ntphdr *ntp, const struct timeval *recvtv);private:    int m_sockfd;};#endif 

NtpClient.cpp

//// Created by lwang on 2023-03-18.//#include "NtpClient.h"NtpClient::NtpClient() { }NtpClient::~NtpClient() {}in_addr_t NtpClient::HostTransfer(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 NtpClient::PaddingNtpPackage(void *buf, size_t *size) // 构建并发送NTP请求报文{    if (!size)        return -1;    struct ntphdr *ntp;    struct timeval tv;    memset(buf, 0, BUFSIZE);    ntp = (struct ntphdr *)buf;    ntp->ntp_li = NTP_LI;    ntp->ntp_vn = NTP_VERSION_NUM;    ntp->ntp_mode = NTP_MODE_CLIENT;    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_MIN_LEN;    return 0;}double NtpClient::GetOffset(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;}void NtpClient::GetNtpTime(std::string &ntpTime){    char buffer[64] = {0};    char cmd[128] = {0};    tm *local;    char buf[BUFSIZE];    size_t nbytes;    int maxfd1;    struct sockaddr_in servaddr;    fd_set readfds;    struct timeval timeout, recvtv, tv;    double offset;    servaddr.sin_family = AF_INET;    servaddr.sin_port = htons(NTP_SERVER_PORT);    servaddr.sin_addr.s_addr = HostTransfer(NTP_SERVER_ADDR);    if ((m_sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0){        perror("socket error");        return ;    }    if (connect(m_sockfd, (struct sockaddr *)&servaddr, sizeof(struct sockaddr)) != 0){        perror("connect error");        return ;    }    nbytes = BUFSIZE;    if (PaddingNtpPackage(buf, &nbytes) != 0){        fprintf(stderr, "construct ntp request error \n");        exit(-1);    }    send(m_sockfd, buf, nbytes, 0);    FD_ZERO(&readfds);    FD_SET(m_sockfd, &readfds);    maxfd1 = m_sockfd + 1;    timeout.tv_sec = TIMEOUT;    timeout.tv_usec = 0;    if (select(maxfd1, &readfds, NULL, NULL, &timeout) > 0){        if (FD_ISSET(m_sockfd, &readfds)){            if ((nbytes = recv(m_sockfd, buf, BUFSIZE, 0)) < 0){                perror("recv error");                exit(-1);            }            // 计算C/S时间偏移量            gettimeofday(&recvtv, NULL);            offset = GetOffset((struct ntphdr *)buf, &recvtv);            gettimeofday(&tv, NULL);            tv.tv_sec += (int)offset;            tv.tv_usec += offset - (int)offset;            local = localtime((time_t *)&tv.tv_sec);            strftime(buffer, 64, "%Y-%m-%d %H:%M:%S", local);            ntpTime = std::string(buffer);        }    }    return ;}

main.cpp

#include "NtpClient.h"int main(){    std::string ntpTime = "";    char curBuf[64] = {0};    struct timeval cur;    tm *local;    NtpClient client;    client.GetNtpTime(ntpTime);    cout << "ntpTime: " << ntpTime << endl;    gettimeofday(&cur, NULL);    local = localtime((time_t *)&cur.tv_sec);    strftime(curBuf, 64, "%Y-%m-%d %H:%M:%S", local);    std::string curTime = std::string(curBuf);    cout << "curTime: " << curTime << endl;    if (curTime != ntpTime){        cout << "start time calibrate!"  << endl;        std::string cmd = "sudo date -s \"" + ntpTime +  "\"";        system(cmd.c_str());        cout << "cmd: " << cmd << endl;    }else{        cout << "time seem"  << endl;    }    return 0;}

推荐一个零声学院免费教程,个人觉得老师讲得不错,
分享给大家:[Linux,Nginx,ZeroMQ,MySQL,Redis,
fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,
TCP/IP,协程,DPDK等技术内容,点击立即学习:

来源地址:https://blog.csdn.net/weixin_46935110/article/details/129683157

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-人工智能
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯