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

这篇具有很好参考价值的文章主要介绍了Linux时间校准(ntpdate及NTP客户端代码校准示例)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

背景

机器每次机启后时间就会出现异常,因为机器无法访问外网,只能访问局域网的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 2023
nvidia@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 2023
nvidia@nvidia-desktop:~$

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

1.2 hwclock 命令
查看当前硬件时间

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

nvidia@nvidia-desktop:~$ hwclock
hwclock: 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 hwclock
2023-03-21 11:18:49.607690+0800
nvidia@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.org
18 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 -e

0 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 <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>
#include <map>
#include <string>
#include <mutex>

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 /* NTP_CLIENT_H */

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://www.toymoban.com/news/detail-443088.html

到了这里,关于Linux时间校准(ntpdate及NTP客户端代码校准示例)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 局域网ntp服务器设置(windows时间同步服务器NetTime)(ubuntu systemd-timesyncd ntp客户端)123端口、ntp校时、ntp同步(设置UDP入站流量绕过防火墙)

    客户有个局域网,局域网里面有的设备,时间都不一致,导致交互的时候可能出现问题; 现在刚好有台主机,有两个以太网接口,其中一个可以连外网,能获取到网络时间,我们可以把这台主机做成ntp服务器,供局域网内其他主机做时间同步; 以下是相关操作方法步骤; 打

    2024年01月24日
    浏览(45)
  • #Centos Centos7配置NTP服务端和客户端

    环境: 服务器:172.16.89.252 客户端:172.16.89.253 NTP公网地址:常见的NTP授时服务器地址 一、配置服务端 1、先安装NTP服务器(服务器是最小安装,不带ntp) 2、配置ntpd服务 配置文件中一般有restrict default语句,注释掉第二种或选择第一种   配置与上级互联网服务端连续性同步

    2024年02月05日
    浏览(33)
  • centos 7 离线安装ntp时钟服务器以及客户端

    1.离线安装包下载地址 下载路径阿里云盘 资源内容包含如下: : 1.找一台服务做时间服务器,将文件夹 ntp-install 放入到 /home 下,执行命令 sh setup 2. 修改/etc/ntp.conf 文件配置. 允许 1192.168.0.0-192.168.0.255 网段内所有机器从 esnode1 同步时间 restrict 192.168.0.0 mask 255.255.255.0 nomodify

    2024年04月26日
    浏览(47)
  • Linux中关于日期和时区的操作(date命令、ntp程序自动校准时间)

    语法: date [-d] [+格式化字符串] -d 按照给定的字符串显示日期,一般用于 日期计算 格式化字符串:通过特定的字符串标记,来控制显示的日期格式 %Y 年          %y 年份后两位数字 (00..99) %m 月份 (01..12) %d 日 (01..31) %H 小时 (00..23) %M 分钟 (00..59) %S 秒 (00..60) %s 自 1970-01-01

    2024年01月16日
    浏览(62)
  • 【ES实战】ES创建Transports客户端时间过长分析

    2023年10月19日 在创建ES Transport客户端的时,当出现以下场景时,影响连接速度。 使用ES Transport 客户端创建与集群的链接。 连接地址里面有不存在的IP 在增加ES节点时,采用逐个增加的方式 整个建立链接的过程会非常耗时。 采用jar依赖如下 创建连接代码如下 输出结果 是否可

    2024年02月07日
    浏览(45)
  • ntpdate解决同步时间报错 the NTP socket is in use, exiting

    今天为了同步服务器时间,使用该命令时会收到下列错误消息。 13 Apr 15:48:18 ntpdate[124176]: the NTP socket is in use, exiting

    2024年02月04日
    浏览(42)
  • 【openfeign】OpenFeign的扩展、日志、超时时间、拦截器、客户端组件、压缩

    有时候我们遇到Bug,比如接口调用失败、参数没收到等问题,或者想看看调用性能,就需要配置Feign的日志了,以此让Feign把请求信息输出来。 定义一个配置类,指定日志级别: 通过源码可以看到日志等级有4种,分别是: NONE:不记录任何日志(默认值),性能最佳,适用于

    2024年02月12日
    浏览(46)
  • TCP四次握手为什么客户端等待的时间是2MSL

    MSL是Maximum Segment Lifetime英文的缩写,中文可以译为“报文最大生存时间”,他是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。 第三次握手服务端发送FIN报文段,最长情况下经过MSL的时间可以到达客户端,客户端在收到来自服务端的FIN报文段之后发送ACK报文

    2024年02月15日
    浏览(50)
  • FTP客户端c代码功能实现

    现在市面上有很多免费的FTP软件:如FileZilla ,那如果想自己在代码中实现与ftp服务器的上传下载文件该如何实现那?  本质上ftp协议就是TCP基础上建立的一种协议,具体如下。 文件传输协议(FTP)作为网络共享文件的传输协议,在网络应用软件中具有广泛的应用。FTP的目标是

    2024年02月02日
    浏览(58)
  • CentOS 7内网服务器NTP时间校准与同步

    服务器时间不同步,最简单粗暴的方法是:直接用命令手动改时间。 先修改时区为上海,再修改时间,所以,so easy ,本文结束… 为什么?难受!这很不优雅,别问我为什么,总之无法接受 自动校准时间 多台服务器同步时间 永久生效,即使重启 有root权限 服务器在内网上不

    2024年02月20日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包