ToB企服应用市场:ToB评测及商务社交产业平台

标题: 基于QT的NTP客户端和服务器端协议和代码详解(1) [打印本页]

作者: 来自云龙湖轮廓分明的月亮    时间: 7 天前
标题: 基于QT的NTP客户端和服务器端协议和代码详解(1)
一 、前言

    近来一段时间一直在弄NTP协议。本来需要做NTP的服务器端程序,但是由于不知道本身编写的代码能不能运行,所以还需要编写NTP客户端程序来验证。最后决定客户端和服务器端程序都需要编写。
二、现有问题  

     前期在网上搜索了很多相关资料,有写NTP客户端程序的,有写NTP服务器端程序的,有介绍NTP协议的。发现问题如下:
(1)客户端方面:程序中仅仅介绍发送和接收方式,却没有介绍怎么设定相关参数。协议方面也仅仅介绍了各个报文对应什么含义,具体怎么添补却没有详细介绍;
(2)服务器端方面:程序很少,而且也没有介绍参数怎么设定,协议方面也和客户端协议一样,对具体数据添补都仅仅停留在含义方面。
三、办理办法

    在现有资料的底子上,起首办理客户端程序问题,而且多次实验程序中具体数据代表意义,而且发送到实际网络中,分析发送报文的可能性和接收报文的可能性,确定发送报文的精确性和接收报文的解析。再次办理服务器端程序问题,分析接收报文和回复报文的具体含义,而且通过已履历证的客户端程序和报文进行模拟,同时接入现有时钟装置进行实际验证,确定接收报文的解析和发送报文的精确性。
    条件条件:(1)网络NTP,可以验证客户端的精确性;(2)自我收发NTP,可以验证客户端和服务器端的互联及模拟;(3)时钟同步装置,可以验证服务器的精确性。
四、客户端

1.协议


    先说下需要添补的量:前置信息(必须)、标识符(非必须)、传送时间戳(必须)。
(1)前置信息:闰秒,版本,模式,层,测试间隔,精度。这几个全部测试过了:
    闰秒主要针对服务器端回复信息,与客户端的添补没有什么关系,所以可以不添补,那就填0,如果你想填其他的也可以,和服务器端回复信息没什么关系。
    版本号也测试过了,是兼容的,客户端填1,2,3都可以,服务器回复的时候都是回复3。应该网上的NTP服务器都是用的3版本。所以添补最新的3就行。网上有的写返回的是最新的版本4,但是我毗连下全部的网络NTP服务器,返回的都是3。
    模式这个是必须填写3,因为是客户端,这个是必须固定的,其他的会出现意想不到的问题。服务器回复的时候回复4。也就是说这个是发送信息者的信息,所以对应添补就行。
    层这个随意,这个界说只针对服务器端的回复报文,所以也都添补成0。
    测试间隔和精度这个也随意,改变之后不改变服务器端回复的报文,所以也都添补成0。
(2)标识符,这个很故意思,这个发送的时候,对于网络NTP服务器没有任何影响。改变之后不改变服务器端回复信息。所以这个也是随意的。但是如果有特别要求的话,需要填入对应字符。
(3)传送时间戳。这个也测试了下,只有填写到最后的位置才能让服务器端返回精确的数据。参考全部网上写的,都是说原始时间戳是客户端发送的时间,其实这个是针对服务器端返回的报文,却不针对客户端报文。其实精确的明白方式应该是,传送时间戳是离开客户端和服务器端的时间,不管是客户端还是服务器端都是要添补这个数据。客户端数据发送时间添补到这里,服务器端数据发送时间也添补到这里,而不是协议里面写的添补到原始时间戳那里。
2.报文解析

    客户端发送报文举例如下:
  1. 1B 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  2. 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 E9 D4 0C E9 91 01 00 00
复制代码
    具体分析下:
1B:0001 1011       00代表无闰秒预告。011代表NTP版本号3。011代表客户端模式。最好如许添补,以免出现兼容问题。
E9 D4 0C E9 91 01 00 00  这个是客户端的传送时间戳。有个问题需要留意,NTP采用的是小端模式,具体为啥不清楚,所以解析的时候必须反过来,也就是:00 00 01 91 E9 0C D4 E9,这个才是真正的时间戳,转化为十进制:1726191817961。这里需要留意:1726191817是秒数,961是毫秒数。使用时间戳转换工具和本身编写的软件转换时间:


    所以这种解析方式是精确的,而且只能如许添补。所以添补步骤:先获得时间戳,记得是毫秒戳,然后转化为8个字节的数据,然后大小端互换,然后添补进去。
其他的都添补0就可以,至于想试试的小同伴可以全部都试试。基本的格式是第1个字节和最后8个字节必须添补好,如许可以从网络NTP服务器中获得精确的时间。
3.程序

    程序编写条件:对QT掌握的熟练,基本的操作是必须得。前面的文章有介绍QT的基本操作,可以看看。对于基本的操作部门仅仅贴出代码,主要介绍和NTP客户端相关的程序。
    这篇文章仅仅介绍NTP客户端的发送程序,至于接收的报文,下篇文章再介绍。

    这个是客户端的界面。程序里面都是根据汉字意思翻译已往的变量,所以应该挺好明白。
    注:编写有交互的软件最好是发送报文和接收报文都体现,如许方便用现有的软件对程序进行调试。这个前期我采用网络调试助手中的UDP去的调试的。很方便。
    程序应该添加什么头文件,这个是必须得。什么pro里面添加network,头文件添加:
  1. #include  <QUdpSocket>
复制代码
这些都是基本操作,就不详细解释了。
初始化阶段程序,形成界面,至于界面做成什么样子,本身修改就行,这里重复代码比较多,所以仅仅是给出个大概。
  1. ntpclient::ntpclient(QWidget *parent) :
  2.     QWidget(parent),
  3.     ui(new Ui::ntpclient)
  4. {
  5.     ui->setupUi(this);
  6.     m_socket=new QUdpSocket(this);
  7.     connect(m_socket, &QUdpSocket::readyRead, this, &ntpclient::on_readData);
  8.     connect(ui->connect,&QPushButton::clicked,this, &ntpclient::myconnect);
  9.     connect(ui->send,&QPushButton::clicked,this, &ntpclient::sendData);
  10.     model = new QStandardItemModel();
  11.     ui->tableView->setModel(model);
  12.     ui->tableView->verticalHeader()->hide();
  13.     ui->tableView->horizontalHeader()->hide();
  14.     ui->tableView->horizontalHeader()->setStretchLastSection(true);
  15.     ui->tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
  16.     ui->tableView->verticalHeader()->setSectionResizeMode(QHeaderView::Stretch);
  17.     for (int i=0;i<10;i++)
  18.     {
  19.         const QStringList rows[] =
  20.         {
  21.             QStringList
  22.             {
  23.                 QString::number(0),QString::number(0),QString::number(0),QString::number(0)
  24.             }
  25.         };
  26.         for (const QStringList &row : rows)
  27.         {
  28.             items.clear();
  29.             for (const QString &text : row)
  30.             {
  31.                 items.append(new QStandardItem(text));
  32.             }
  33.             model->appendRow(items);
  34.         }
  35.     }
  36.     uint8_t row;
  37.     row = model->rowCount();
  38.     for (int i=0;i<row;i++)
  39.     {
  40.         model->item(i,0)->setTextAlignment(Qt::AlignCenter);
  41.         model->item(i,1)->setTextAlignment(Qt::AlignCenter);
  42.         model->item(i,2)->setTextAlignment(Qt::AlignCenter);
  43.         model->item(i,3)->setTextAlignment(Qt::AlignCenter);
  44.     }
  45.     model->item(0,0)->setText("闰秒");
  46.     model->item(0,0)->setBackground(QColor("LightGray"));
  47.     ui->tableView->setStyleSheet("gridline-color: rgb(0, 0, 0)");
  48. }
复制代码
固然对应h文件里面也需要添加对应变量,放进去之后本身调试下就行,相关基本操作就不再一一说了,认识QT的应该挺容易明白的。
  1. #include <QUdpSocket>
  2. #include <QStandardItemModel>   
  3.     QUdpSocket *m_socket;
  4.     QByteArray toNtpPacket();
  5.     void myconnect();
  6.     void connectServer(QString url);        // 连接Ntp服务
  7.     void close();
  8.     QStandardItemModel *model;
  9.     QList<QStandardItem *> items;
复制代码
如许基本的工作就做好了。下面介绍和NTP客户端相关的发送程序。
第一个:毗连NTP服务器。这个包含2个:本身的服务器,网络服务器。
  1. void ntpclient::myconnect()
  2. {
  3.     connectServer("ntp.tencent.com");
  4. //    connectServer("127.0.0.1");
  5. }
  6. void ntpclient::connectServer(QString url)
  7. {
  8.     m_socket->connectToHost(url, 123);
  9.     if(m_socket->waitForConnected())
  10.     {
  11.         qDebug() << "连接成功";
  12.     }
  13.     else
  14.     {
  15.         qDebug() << "连接失败";
  16.     }
  17. }
复制代码
    主要两个参数:IP需要改变。PORT是固定的123。
    网络NTP服务器,那么填入需要的网站,这个搜素的话有很多,选一个能用的。留意:腾讯的比较快,其他的都测试了都比较慢,而且有的毗连不上,所以最好选用这个,测试方便。端口号肯定是123。这个是应规定,NTP服务器就是用的这个端口号。
    本身的服务器:这个又分为两种,同一台电脑上,两台电脑上。
    同一台电脑:IP是127.0.0.1。为啥是这个,我用网络助手和本身最后编程的软件都测试过了。本身的电脑是本身假造本身的IP地点,如果采用同一台电脑模拟客户端和服务器端的话,IP就是
这个。客户端和服务器端都是这个,而且这个端口他也会本身假造出来一个端口用。所以这个没办法。
    两台电脑上:一台电脑上客户端,另一台电脑服务器端。如许如许IP就是本身的物理地点。留意:由于采用UDP模式,两台电脑可以用网线直接互联,这个测试过了,不需要路由器啥的,直接网线怼一起就行。
    前期没有服务器端代码,只能采用网络调试助手去调试,互联一下,看看网络助手能不能接收到数据,能接收到就行,乱码也行,说明路通了。然后再一步一步的修改代码,直至得到精确的数据。
第二个:添补报文。
  1. QByteArray ntpclient::toNtpPacket()
  2. {
  3.     QByteArray result(40, 0);
  4.     quint8 li = 0;                   // LI闰秒标识器,占用2个bit,0 即可;
  5.     quint8 vn = 3;                   // VN 版本号,占用3个bits,表示NTP的版本号,现在为3;
  6.     quint8 mode = 3;                 // Mode 模式,占用3个bits,表示模式。 3 表示 client, 2 表示 server
  7.     quint8 stratum = 0;              // 系统时钟的层数,取值范围为1~16,它定义了时钟的准确度。层数为1的时钟准确度最高,准确度从1到16依次递减,层数为16的时钟处于未同步状态,不能作为参考时钟。
  8.     quint8 poll = 0;                 // 轮询时间,即两个连续NTP报文之间的时间间隔(4-14)
  9.     qint8 precision = 0;             // 系统时钟的精度,精确到秒的平方级(-6 到 -20)
  10.     result[0] = char((li << 6) | (vn <<3) | (mode));
  11.     result[1] = char(stratum & 0xff);
  12.     result[2] = char(poll & 0xff);
  13.     result[3] = char(precision & 0xff);
  14.     qint64 currentLocalTimestamp = QDateTime::currentMSecsSinceEpoch();
  15.     result.append((const char *)&currentLocalTimestamp, sizeof(qint64));
  16.     qDebug()<<currentLocalTimestamp;
  17.     return result;
  18. }
复制代码
    里面添补和前面介绍的一样。为了方便取了40个数据,反面直接append,就把时间戳给加上了。里面的QDateTime::currentMSecsSinceEpoch()已经将数据转化好了,毫秒戳,大小端互换,所以直接添补就好。
    题外话:这个数据就解析的很烦躁,不知道他的解析规则,只能本身猜,为啥,为啥,为啥又不对。最后找了很多文章才发现是大小端互换,而且反面是3位毫秒。所以数据出来的时候都不知道为啥是这个。为啥和网络的时间戳对不上,怎么都解析不出来。最后才发现是如许解析的。
第三个:发送报文
  1. void ntpclient::sendData()
  2. {
  3.     QByteArray arr = toNtpPacket();
  4.     qint64 len = m_socket->write(arr);
  5.     if(len != arr.count())
  6.     {
  7.         qWarning() << "发送NTP请求帧失败:" << arr.toHex(' ');
  8.     }
  9.     uint8_t gnReceiveData[48];
  10.     ui->textEdit_2->clear();
  11.     for(int i=0; i<48; i++)
  12.     {
  13.         gnReceiveData[i] = arr[i];
  14.         ui->textEdit_2->insertPlainText(QString("%1").arg(gnReceiveData[i],2,16,QLatin1Char('0')).toUpper());
  15.         ui->textEdit_2->insertPlainText(" ");
  16.     }
  17. }
复制代码
    直接发送字符,然后在ui界面体现发送报文。
至此客户端发送程序完毕。
五、写在最后

    协议这东西,得慢慢的磨,没办法的事情。有些如果别人写的不清楚就得本身慢慢的去测试,直到测试乐成的时候。期间会很烦躁,怎么这不对,怎么那不对。最后还是得静下心去慢慢搞。固然如果赶的特别紧的话,就很烦人了。有些东西是快不得的,还是得一步一步按照本身的节奏了。
    协议都不难,明白了都没啥问题,程序也应该没啥问题。可以说这部门是时间活,是繁琐点,而不是难点。最重要的是静下心来弄。如果时间不够,那就没办法,只能加班了。
    写完文章之后会将代码放进公众号里面,由于如今不能贴公众号的二维码,所以只能翻看以前的文章去找二维码。需要的小同伴可以关注喜好,未来会放在百度网盘里自行下载。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4