• Qt开源作品29-NTP服务器时间同步


    一、前言

    很多软件都有时间同步的功能,尤其是Qt在嵌入式设备上的,有时候还有很多是没有UI界面的程序,而硬件上有个时钟,时间久了难免没有电,需要从服务器来同步时间来保证本地的时间是正确的,不然本地记录的一些日志的时间都是不正确的,很多还可能是1970年的。
    NTP同步时间是个标准的协议,使用的端口是123端口,这个端口很牛逼,居然霸占了123这个端口,碉堡!使用NTP服务同步时间,需要设置个时间服务器IP地址,这个地址可以网上找到很多的,微软自带的那个有时候行有时候不行,因为默认用的UDP协议,所以是不可靠的,有丢包的可能,建议选择一些国内的时间服务器,比如一些大学的时间服务器,还是比较准确可靠的。

    二、代码思路

    NtpClient::NtpClient(QObject *parent) : QObject(parent)
    {
        ntpIP = "202.120.2.101";
    
        udpSocket = new QUdpSocket(this);
        connect(udpSocket, SIGNAL(connected()), this, SLOT(sendData()));
        connect(udpSocket, SIGNAL(readyRead()), this, SLOT(readData()));
    }
    
    void NtpClient::sendData()
    {
        qint8 LI = 0;
        qint8 VN = 3;
        qint8 MODE = 3;
        qint8 STRATUM = 0;
        qint8 POLL = 4;
        qint8 PREC = -6;
        QDateTime epoch(QDate(1900, 1, 1));
        qint32 second = quint32(epoch.secsTo(QDateTime::currentDateTime()));
    
        qint32 temp = 0;
        QByteArray timeRequest(48, 0);
        timeRequest[0] = (LI << 6) | (VN << 3) | (MODE);
        timeRequest[1] = STRATUM;
        timeRequest[2] = POLL;
        timeRequest[3] = PREC & 0xff;
        timeRequest[5] = 1;
        timeRequest[9] = 1;
        timeRequest[40] = (temp = (second & 0xff000000) >> 24);
        temp = 0;
        timeRequest[41] = (temp = (second & 0x00ff0000) >> 16);
        temp = 0;
        timeRequest[42] = (temp = (second & 0x0000ff00) >> 8);
        temp = 0;
        timeRequest[43] = ((second & 0x000000ff));
    
        udpSocket->write(timeRequest);
    }
    
    void NtpClient::readData()
    {
        QByteArray newTime;
        QDateTime epoch(QDate(1900, 1, 1));
        QDateTime unixStart(QDate(1970, 1, 1));
    
        while (udpSocket->hasPendingDatagrams()) {
            newTime.resize(udpSocket->pendingDatagramSize());
            udpSocket->read(newTime.data(), newTime.size());
        };
    
        QByteArray transmitTimeStamp ;
        transmitTimeStamp = newTime.right(8);
        quint32 seconds = transmitTimeStamp.at(0);
        quint8 temp = 0;
    
        for (int i = 1; i <= 3; i++) {
            seconds = (seconds << 8);
            temp = transmitTimeStamp.at(i);
            seconds = seconds + temp;
        }
    
        QDateTime dateTime;
        dateTime.setTime_t(seconds - epoch.secsTo(unixStart));
    
    #ifdef __arm__
    #ifdef arma9
        dateTime = dateTime.addSecs(60 * 60 * 8);
    #endif
    #endif
        udpSocket->disconnectFromHost();
    
        //有些时候返回的数据可能有误或者解析不正确,导致填充的时间不正确
        if (dateTime.isValid()) {
            emit receiveTime(dateTime);
        }
    }
    
    void NtpClient::setNtpIP(const QString &ntpIP)
    {
        if (this->ntpIP != ntpIP) {
            this->ntpIP = ntpIP;
        }
    }
    
    void NtpClient::getDateTime()
    {
        udpSocket->abort();
        udpSocket->connectToHost(ntpIP, 123);
    }
    

    三、效果图

    四、开源主页

    以上作品完整源码下载都在开源主页,会持续不断更新作品数量和质量,欢迎各位关注。

    1. 国内站点:https://gitee.com/feiyangqingyun/QWidgetDemo
    2. 国际站点:https://github.com/feiyangqingyun/QWidgetDemo
    3. 个人主页:https://blog.csdn.net/feiyangqingyun
    4. 知乎主页:https://www.zhihu.com/people/feiyangqingyun/
  • 相关阅读:
    .Net中获取打印机的相关信息
    如何在windows server 2008上配置NLB群集
    jvm分析内存泄露
    JVM调优
    线程池工作队列饱和策略
    线程池的处理流程:
    Java的Executor框架和线程池实现原理(转)
    线程池实现原理详解:
    futer.get()(如果任务没执行完将等待)
    sql注入
  • 原文地址:https://www.cnblogs.com/feiyangqingyun/p/13059665.html
Copyright © 2020-2023  润新知