此篇博文讲解了DTLS客户端的编写

注意:DTLS客户端需要结合DTLS服务端一起跑才有效果。

这里使用DTLS客户端使用少量的连接可以和一个或多个DTLS服务端进行通信。DtlsAssociation是DTLS客户端连接类。这个类使用了QudpSocket去进行数据报的读写,使用QDtls进行数据报的加密:

  class DtlsAssociation : public QObject{Q_OBJECTpublic:DtlsAssociation(const QHostAddress &address, quint16 port,const QString &connectionName);~DtlsAssociation();void startHandshake();signals:void errorMessage(const QString &message);void warningMessage(const QString &message);void infoMessage(const QString &message);void serverResponse(const QString &clientInfo, const QByteArray &datagraam,const QByteArray &plainText);private slots:void udpSocketConnected();void readyRead();void handshakeTimeout();void pskRequired(QSslPreSharedKeyAuthenticator *auth);void pingTimeout();private:QString name;QUdpSocket socket;QDtls crypto;QTimer pingTimer;unsigned ping = 0;Q_DISABLE_COPY(DtlsAssociation)};

构造函数中最小化配置了TLS,用于DTLS连接的创建,以及配置了IP地址和端口:

      ...auto configuration = QSslConfiguration::defaultDtlsConfiguration();configuration.setPeerVerifyMode(QSslSocket::VerifyNone);crypto.setPeer(address, port);crypto.setDtlsConfiguration(configuration);...

QDtls::handshakeTimeout()信号与handleTimeout()槽函数相关联,处理有问题的数据报,和握手时出现问题时数据的重发:

      ...connect(&crypto, &QDtls::handshakeTimeout, this, &DtlsAssociation::handshakeTimeout);...

使用UDPSocket连接到服务端:

      ...socket.connectToHost(address.toString(), port);...

QUdpSocket::readyRead()信号与readyRead()槽函数相关联

      ...connect(&socket, &QUdpSocket::readyRead, this, &DtlsAssociation::readyRead);...

当一条加密的连接创建后,DtlsAssociation对象会发送一条简短的ping消息到服务端:

  pingTimer.setInterval(5000);connect(&pingTimer, &QTimer::timeout, this, &DtlsAssociation::pingTimeout);

startHandshake()函数用于与服务端的握手:

  void DtlsAssociation::startHandshake(){if (socket.state() != QAbstractSocket::ConnectedState) {emit infoMessage(tr("%1: connecting UDP socket first ...").arg(name));connect(&socket, &QAbstractSocket::connected, this, &DtlsAssociation::udpSocketConnected);return;}if (!crypto.doHandshake(&socket))emit errorMessage(tr("%1: failed to start a handshake - %2").arg(name, crypto.dtlsErrorString()));elseemit infoMessage(tr("%1: starting a handshake").arg(name));}

readyRead()槽函数读取服务端传输过来的数据:

  QByteArray dgram(socket.pendingDatagramSize(), Qt::Uninitialized);const qint64 bytesRead = socket.readDatagram(dgram.data(), dgram.size());if (bytesRead <= 0) {emit warningMessage(tr("%1: spurious read notification?").arg(name));return;}dgram.resize(bytesRead);

如果握手已经完成,随后就是数据的加密了:

  if (crypto.isConnectionEncrypted()) {const QByteArray plainText = crypto.decryptDatagram(&socket, dgram);if (plainText.size()) {emit serverResponse(name, dgram, plainText);return;}if (crypto.dtlsError() == QDtlsError::RemoteClosedConnectionError) {emit errorMessage(tr("%1: shutdown alert received").arg(name));socket.close();pingTimer.stop();return;}emit warningMessage(tr("%1: zero-length datagram received?").arg(name));} else {

如果出现错误,就继续进行握手:

      if (!crypto.doHandshake(&socket, dgram)) {emit errorMessage(tr("%1: handshake error - %2").arg(name, crypto.dtlsErrorString()));return;}

当握手完成,就发送第一个ping消息:

      if (crypto.isConnectionEncrypted()) {emit infoMessage(tr("%1: encrypted connection established!").arg(name));pingTimer.start();pingTimeout();} else {

pskRequired()槽函数在握手期间提供了Pre-Shared Key(PSK)

  void DtlsAssociation::pskRequired(QSslPreSharedKeyAuthenticator *auth){Q_ASSERT(auth);emit infoMessage(tr("%1: providing pre-shared key ...").arg(name));auth->setIdentity(name.toLatin1());auth->setPreSharedKey(QByteArrayLiteral("\x1a\x2b\x3c\x4d\x5e\x6f"));}

上面的代码是比较简洁的,QSslPreSharedKeyAuthenticator类讲解了如何正确的设置PSK及证书相关的设置。

pingTimeout()向服务端发送机密数据:

  void DtlsAssociation::pingTimeout(){static const QString message = QStringLiteral("I am %1, please, accept our ping %2");const qint64 written = crypto.writeDatagramEncrypted(&socket, message.arg(name).arg(ping).toLatin1());if (written <= 0) {emit errorMessage(tr("%1: failed to send a ping - %2").arg(name, crypto.dtlsErrorString()));pingTimer.stop();return;}++ping;}

在握手期间,客户端需要处理超时丢包的现象,这里使用handshakeTimeout()进行处理:

  void DtlsAssociation::handshakeTimeout(){emit warningMessage(tr("%1: handshake timeout, trying to re-transmit").arg(name));if (!crypto.handleTimeout(&socket))emit errorMessage(tr("%1: failed to re-transmit - %2").arg(name, crypto.dtlsErrorString()));}

析构函数中销毁DTLS的连接:

  DtlsAssociation::~DtlsAssociation(){if (crypto.isConnectionEncrypted())crypto.shutdown(&socket);}

错误消息,提示消息,收到服务端的返回值都展示到UI界面上了:

  const QString colorizer(QStringLiteral("<font color=\"%1\">%2</font><br>"));void MainWindow::addErrorMessage(const QString &message){ui->clientMessages->insertHtml(colorizer.arg(QStringLiteral("Crimson"), message));}void MainWindow::addWarningMessage(const QString &message){ui->clientMessages->insertHtml(colorizer.arg(QStringLiteral("DarkOrange"), message));}void MainWindow::addInfoMessage(const QString &message){ui->clientMessages->insertHtml(colorizer.arg(QStringLiteral("DarkBlue"), message));}void MainWindow::addServerResponse(const QString &clientInfo, const QByteArray &datagram,const QByteArray &plainText){static const QString messageColor = QStringLiteral("DarkMagenta");static const QString formatter = QStringLiteral("<br>---------------""<br>%1 received a DTLS datagram:<br> %2""<br>As plain text:<br> %3");const QString html = formatter.arg(clientInfo, QString::fromUtf8(datagram.toHex(' ')),QString::fromUtf8(plainText));ui->serverMessages->insertHtml(colorizer.arg(messageColor, html));}

Qt文档阅读笔记-DTLS client解析相关推荐

  1. Qt文档阅读笔记-DTLS server解析

    此篇博文展示了如何创建一个简单的DTLS服务端: 注意:这个DTLS服务端需要和DTLS客户端一起跑,才能看出效果. 服务端实现了DtlsServer类,这个类使用了QUdpSocket,QDtlsC ...

  2. Qt文档阅读笔记-Fortune Client Example实例解析

    目录 官方解析 实例代码 博主增加解析 官方解析 Fortune Client Example 以使用QTcpSocket为例子,服务端可以配合Fortune Server或Threaded Fort ...

  3. Qt文档阅读笔记-QSet官方解析及实例

    目录 官方解析 博主栗子 官方解析 QSet类是一个模板类,他是一个哈希表集合. QSet<T>是Qt的一个普通容器类.QSet存储的值是不指明顺序的,QSet对这些值提供了快速检索的功能 ...

  4. Qt文档阅读笔记-QSslConfiguration官方解析与实例

    目录 官网解析 博主例子 官网解析 QSslConfiguration用于SSL连接的配置. QSslConfiguration是Qt networking下的一个类,这个类主要用于打开SSL连接,以 ...

  5. Qt文档阅读笔记-QtWebApp官方解析与实例(使用QtWebApp搭建HTTP服务器)

    目录 官方解析 博主例子 官方解析 QtWepApp是一个C++的http服务器,受到了java Servlets的启发,因为是Qt写的,所以有跨平台的支持. QtWebApp包含如下的组成部分:   ...

  6. Qt文档阅读笔记-QHostInfo官方解析与实例(根据Host获取IP)

    官方解析 QHostInfo提供了一个静态方法获取主机名: QHostInfo中有一个查找机制,可以根据IP找主机名,也可能工具主机名找IP,可以通过调用QHostInfo::lookupHost这个 ...

  7. Qt文档阅读笔记-QTcpServer官方解析与实例(使用QSocket创建简单的HTTP服务器)

    目录 官方解析 博主例子(做一个简单的HTTP服务器) 本例子中HTTP协议关键点 官方解析 QTcpServer类,提供TCP服务的基础: 这个类接受TCP连接,可以指定一个端口,也可以让其自动一个 ...

  8. Qt文档阅读笔记-QWebPage官方解析与实例

    目录 官方解析 博主例子 源码下载地址 官方解析 QWebPage提供一个视图对象和一个web页面: QWebPage提供了web页面的内容,各种设置(是否支持JavaScript等)和连接,它与QW ...

  9. Qt文档阅读笔记-QWebView官方解析与实例

    目录 背景 官方解析 博主例子 背景 最近发现某Qt项目,出现的效果杠杆的,在看某一小功能的时候,发现有个echart的东西,百度了发现,真的是一个新大陆,Qt加web编程,贼吉尔可怕. 在此发现使用 ...

最新文章

  1. PowerDesigner 常用设置
  2. Cloudify — OpenStack Infrastructure Plugin V3
  3. CTFshow php特性 web111
  4. 1.3 torch_向量/矩阵操作
  5. RabbitMQ延迟消费和重复消费
  6. 万维网服务器协议提供web,万维网的HTTP和FTP协议.doc
  7. java实现人脸识别源码【含测试效果图】——Service层(IUserService)
  8. Tips--解决安装matplotlib无法使用pyplot的问题
  9. MFC中Combo 下来菜单不能展开(只显示一点点)
  10. 介绍如何隐藏JDataGridBean的SplashScreen?
  11. 闭包 python_Python闭包思想与用法浅析
  12. php invoke 反射,PHP ReflectionMethod invoke()用法及代码示例
  13. PHP 实现-多线程编程
  14. CS中mdl文件的解析
  15. 路由器mac地址克隆
  16. 打造一款CPS返佣小程序之创建淘宝联盟账号及获取饿了么佣金路径《二》
  17. diy计算机英语,电脑组装DIY基本英语单词
  18. 【通信仿真】Aloha协议仿真含Matlab源码
  19. 怎么用计算机计算年月份,win7计算器怎么计算某年某月某日到某年某 – 手机爱问...
  20. 2021年6月国产数据库大事记

热门文章

  1. 2022-05-17 C++读入二进制文件并输出二进制文件
  2. 电脑重启bootmgr_开机提示bootmgr is compressed无法启动的方法,看完就明白了
  3. 中国煤矸石工业市场运行现状与十四五投资潜力分析报告2022版
  4. 菜鸟初次安装CP2K笔记
  5. python 爬取东方财富股吧论坛个股评论信息
  6. 256色图像不一定是灰度图像
  7. ligerui tree mysql_jQuery LigerUI ligerGrid 在开发中的应用记录
  8. 无线网络渗透-1: 802.11 AP扫描
  9. 扫码枪扫描二维码to值到pc端
  10. 基于Pytorch的语音情感识别系统