mqtt服务器搭建与qt下的mqtt客户端实现

news2024/11/26 20:31:32

一、mqtt介绍

  MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议),是一个基于客户端-服务器的消息发布/订阅传输协议。MQTT协议是轻量、简单、开放和易于实现的,这些特点使它适用范围非常广泛。在很多情况下,包括受限的环境中,如:机器与机器(M2M)通信和物联网(IoT)。其在,通过卫星链路通信传感器、偶尔拨号的医疗设备、智能家居、及一些小型化设备中已广泛使用。

  MQTT有三种角色的存在:
      Broker代理:很多人理解为中间件,当然可以这样子认为。他就是一个中间件。用于处理信息并发送到相应的订阅者。
      发布者:用于发布信息到代理上面。注意:发布者也可以是订阅者。
      订阅者:就是用于接受信息的客户端。

  MQTT使用TCP/IP提供网络连接,主流的MQTT是基于TCP连接进行数据推送的,但是同样有基于UDP的版本,叫做MQTT-SN

  三种消息发布服务质量:
    “至多一次”,消息发布完全依赖底层TCP/IP网络。会发生消息丢失或重复。这一级别可用于如下情况,环境传感器数据,丢失一次读记录无所谓,因为不久后还会有第二次发送。这一种方式主要普通APP的推送,倘若你的智能设备在消息推送时未联网,推送过去没收到,再次联网也就收不到了。
    “至少一次”,确保消息到达,但消息重复可能会发生。
    “只有一次”,确保消息到达一次。在一些要求比较严格的计费系统中,可以使用此级别。在计费系统中,消息重复或丢失会导致不正确的结果。这种最高质量的消息发布服务还可以用于即时通讯类的APP的推送,确保用户收到且只会收到一次

  MQTT协议中的方法:
    Connect:等待与服务器建立连接
    Disconnect:等待MQTT客户端完成所作的工作,并于服务器断开TCP/IP会话
    Subscribe:等待完成订阅
    UnSubscribe:等待服务器取消客户端的一个活多个和topics订阅
    Publish:MQTT客户端发送消息请求,发送完成后返回应用程序线程

  优点:
    低开销、低带宽占用,可以以极少的代码和有限的带宽,为连接远程设备提供实时可靠的消息服务。

二、在windows上安装mqtt服务器:

1.mosquitto介绍

  Mosquitto是一款实现了消息推送协议MQTT 3.1的开源消息代理软件,提供轻量级的、支持可订阅/可发布的消息推送模式,是设备与设备之间的短消息通信变得简单,广泛应用于低功耗传感器、手机(app消息推送是场景之一)、嵌入式电脑、微型控制器等移动设备。

2.下载mosquitto

下载地址:https://mosquitto.org/download/
在这里插入图片描述

3.安装mosquitto

在这里插入图片描述
在这里插入图片描述

4.配置文件修改

4.1 mosquitto.conf文件修改

在这里插入图片描述

4.2 以管理员身份打开Windows PowerShell, 进行用户密码配置

在这里插入图片描述

4.3 重启mosquitto broker服务

在这里插入图片描述

4.4 测试服务器

在这里插入图片描述

三、编译qtmqtt和创建mqtt客户端工程

Qt在5.10版本开始支持mqtt,但是也没有集成到安装包里面,需要自己下载编译

1.先下载安装Perl (解决编译qtmqtt报perl错误)

下载地址:https://www.perl.org/get.html
ActivePerl_x64_5.24.1.2402.exe

2.下载安装qtmqtt

下载地址:https://github.com/emqx/qmqtt

打开工程文件,选择src执行qmake,然后点击构建即可生成相应的库文件
在这里插入图片描述

3.创建myMqttDemo客户端工程

在这里插入图片描述
在这里插入图片描述

我的demo工程下载地址:https://download.csdn.net/download/linyibin_123/87280629

4.拷贝链接库与头文件到demo工程指定位置

4.1 拷贝头文件:

在这里插入图片描述

4.2 拷贝库文件:

在这里插入图片描述
在这里插入图片描述

4.3 demo工程引用库文件:

在这里插入图片描述
在这里插入图片描述

四、mqtt客户端demo工程代码

mqttClient.h

#ifndef MQTTCLIENT_H
#define MQTTCLIENT_H

#include <QObject>
#include "qmqtt.h"

class mqttClient : public QObject
{
    Q_OBJECT
public:
    mqttClient();

    static mqttClient& getInstance();

    void init(QString sIp, quint16 nPort, QString sClientId, QString sUser, QString sPwd);
private:
    QMQTT::Client *m_pClient;

signals:
    void sig_result_connect();
    void sig_result_disconnect();
    void sig_result_dataReceived(QMQTT::Message message);

public slots:
    void slot_connect();
    void slot_disconnect();
    void slot_publish(QString sTopic, QString sPayload);
    void slot_subscribe(QString sTopic);
    void slot_unSubscribe(QString sTopic);

    void on_dataReceived(QMQTT::Message message);

};

#endif // MQTTCLIENT_H

mqttClient.cpp

#include "mqttclient.h"

mqttClient::mqttClient()
{
    m_pClient = nullptr;
}

mqttClient &mqttClient::getInstance()
{
    static mqttClient s_obj;
    return s_obj;
}

void mqttClient::init(QString sIp, quint16 nPort, QString sClientId, QString sUser, QString sPwd)
{
    if(m_pClient)
    {
        delete m_pClient;
        m_pClient = nullptr;
    }
    m_pClient = new QMQTT::Client(QHostAddress(sIp), nPort);
    if(m_pClient)
    {
        qDebug() << "m_pClient Create Success.";
        m_pClient->setClientId(sClientId);
        m_pClient->setUsername(sUser);
        m_pClient->setPassword(sPwd.toLatin1());
        m_pClient->setKeepAlive(60);

        connect(m_pClient, &QMQTT::Client::connected, this, &mqttClient::sig_result_connect);
        connect(m_pClient, &QMQTT::Client::disconnected, this, &mqttClient::sig_result_disconnect);
        connect(m_pClient, SIGNAL(received(QMQTT::Message)), this, SLOT(on_dataReceived(QMQTT::Message)));
    }
}

void mqttClient::slot_connect()
{
    qDebug() << "connect 000";
    if(m_pClient)
    {
        if(!m_pClient->isConnectedToHost())
        {
            qDebug() << "connect 111";
            m_pClient->connectToHost();
        }
    }
}

void mqttClient::slot_disconnect()
{
    qDebug() << "disconnect";
    if(m_pClient->isConnectedToHost())
    {
        m_pClient->disconnectFromHost();
    }
}

void mqttClient::slot_publish(QString sTopic, QString sPayload)
{
    if(sTopic.isEmpty() || sPayload.isEmpty())
    {
        qDebug() << "sTopic or sPayload is empty";
        return;
    }
    QMQTT::Message message(136, sTopic, sPayload.toUtf8());
    m_pClient->publish(message);
}

void mqttClient::slot_subscribe(QString sTopic)
{
    if(sTopic.isEmpty())
    {
        qDebug() << "sTopic is empty";
        return;
    }
    m_pClient->subscribe(sTopic);
}

void mqttClient::slot_unSubscribe(QString sTopic)
{
    if(sTopic.isEmpty())
    {
        qDebug() << "sTopic is empty";
        return;
    }
    m_pClient->unsubscribe(sTopic);
}

void mqttClient::on_dataReceived(QMQTT::Message message)
{
    qDebug() << "on_dataReceived";
    emit sig_result_dataReceived(message);
}

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "mqttclient.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

signals:
    void sig_btn_connect();
    void sig_btn_disconnect();
    void sig_btn_publish(QString sTopic, QString sPayload);
    void sig_btn_subscribe(QString sTopic);
    void sig_btn_unSubscribe(QString sTopic);

private slots:
    void on_pushButton_Connect_clicked();
    void on_pushButton_Publish_clicked();
    void on_pushButton_Subscribe_clicked();
    void on_pushButton_UnScribe_clicked();

    void slot_result_connect();
    void slot_result_disconnect();
    void slot_result_dataReceived(QMQTT::Message message);


    void on_pushButton_DisConnect_clicked();

private:
    Ui::MainWindow *ui;

};

#endif // MAINWINDOW_H


mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    connect(this, SIGNAL(sig_btn_connect()),
            &mqttClient::getInstance(), SLOT(slot_connect()));
    connect(this, SIGNAL(sig_btn_disconnect()),
            &mqttClient::getInstance(), SLOT(slot_disconnect()));
    connect(this, SIGNAL(sig_btn_publish(QString, QString)),
            &mqttClient::getInstance(), SLOT(slot_publish(QString, QString)));
    connect(this, SIGNAL(sig_btn_subscribe(QString)),
            &mqttClient::getInstance(), SLOT(slot_subscribe(QString)));
    connect(this, SIGNAL(sig_btn_unSubscribe(QString)),
            &mqttClient::getInstance(), SLOT(slot_unSubscribe(QString)));

    connect(&mqttClient::getInstance(), SIGNAL(sig_result_connect()),
            this, SLOT(slot_result_connect()));
    connect(&mqttClient::getInstance(), SIGNAL(sig_result_disconnect()),
            this, SLOT(slot_result_disconnect()));
    connect(&mqttClient::getInstance(), SIGNAL(sig_result_dataReceived(QMQTT::Message)),
            this, SLOT(slot_result_dataReceived(QMQTT::Message)));
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_pushButton_Connect_clicked()
{
    QString sIp = ui->lineEdit_IP->text().trimmed();
    quint16 nPort = (quint16)ui->lineEdit_Port->text().toInt();
    QString sClientId = ui->lineEdit_ClientId->text().trimmed();
    QString sUser = ui->lineEdit_User->text().trimmed();
    QString sPwd = ui->lineEdit_Password->text().trimmed();
    mqttClient::getInstance().init(sIp, nPort, sClientId, sUser, sPwd);

    emit sig_btn_connect();
}

void MainWindow::on_pushButton_Publish_clicked()
{
    QString sTopic = ui->lineEdit_Topic->text().trimmed();
    QString sPayload = ui->lineEdit_Message->text().trimmed();

    emit sig_btn_publish(sTopic, sPayload);
}

void MainWindow::on_pushButton_Subscribe_clicked()
{
    QString sTopic = ui->lineEdit_Topic_2->text().trimmed();
    emit sig_btn_subscribe(sTopic);
}

void MainWindow::on_pushButton_UnScribe_clicked()
{
    QString sTopic = ui->lineEdit_Topic_2->text().trimmed();
    emit sig_btn_unSubscribe(sTopic);
}

void MainWindow::slot_result_connect()
{
    qDebug() << "result:Connected";
    ui->label_Status->setText("Connected");
}

void MainWindow::slot_result_disconnect()
{
    qDebug() << "result:Unconnected";
    ui->label_Status->setText("Unconnected");
}

void MainWindow::slot_result_dataReceived(QMQTT::Message message)
{
    QString sMes = QString(message.id()) + " " + QString(message.qos()) + QString(message.topic()) + message.payload() + "\n";
    ui->textEdit_Log->append(sMes);

}

void MainWindow::on_pushButton_DisConnect_clicked()
{
    emit sig_btn_disconnect();
}

五、客户端与服务器连接调试结果

开启Windows PowerShell,执行服务和订阅发布操作,开启程序连接服务器,并执行订阅和发布操作,双方都可以收到对方发布的消息。

在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/92376.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

前端基础(九)_CSS的三大特征

CSS的三大特征 1、层叠性 1.样式冲突&#xff0c;遵循就近原则 2.样式不冲突&#xff0c;不会层叠&#xff0c;会叠加 1.1.样式冲突&#xff0c;遵循就近原则例子&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UT…

[附源码]Nodejs计算机毕业设计基于的服装商城系统Express(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程。欢迎交流 项目运行 环境配置&#xff1a; Node.js Vscode Mysql5.7 HBuilderXNavicat11VueExpress。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分…

Java优雅的记录日志:log4j实战篇

写在前面 项目开发中&#xff0c;记录错误日志有以下好处&#xff1a; 方便调试 便于发现系统运行过程中的错误 存储业务数据&#xff0c;便于后期分析 在java中&#xff0c;记录日志有很多种方式&#xff1a; 自己实现&#xff1a;自己写类&#xff0c;将日志数据&#xf…

HTTP Range:范围请求

文章目录HTTP 范围请求HTTP 范围请求 Range 头是在 HTTP/1.1 协议中新增的一个请求头。包含 Range 头的请求通常称为范围请求&#xff0c;因为 Range 头允许服务器只发送部分响应到客户端&#xff0c;它是下载工具&#xff08;例如迅雷&#xff09;实现多线程下载的核心所在&a…

Python -- 列表

目录 1.列表的基本使用 1.1 列表的格式 1.2 使用下标获取列表元素 2.列表的增删改查 2.1 添加元素 2.2 修改元素 2.3 查找元素 2.4 删除元素 2.5 排序&#xff08;sort、reverse&#xff09; 3.列表遍历 3.1 使用while循环 3.2 使用for循环 4.列表的嵌套 1.列表的基本…

面向切面编程 AOP

AOPAOP的概念AOP &#xff08;底层原理&#xff09;AOP 底层使用动态代理AOP &#xff08; JDK 动态代理&#xff09;首先我们来看一下 Spring 的百度百科   Spring 框架是一个开放源代码的 J2EE 应用程序框架&#xff0c;由 Rod Johnson 发起&#xff0c;是针对 Bean 的生命…

cpp项目中遇到的一些错误

1.解决由于找不到xxx.dll&#xff0c;无法继续执行代码的问题 解决由于找不到xxx.dll&#xff0c;无法继续执行代码的问题_happylife_mini的博客-CSDN博客_由于找不到emp.dll无法继续执行代码在用vs写项目&#xff0c;或者你下载github上的C代码的时候&#xff0c;是不是经常遇…

【Redis技术探索】「底层架构原理」探索分析服务系统的网络架构和线程模型

Redis网络基础架构 网络编程离不开Socket&#xff0c;网络I/O模型最常用的无非是同步阻塞、同步非阻塞、异步阻塞、异步非阻塞&#xff0c;高性能网络服务器最常见的线程模型也就是基于EventLoop模式的单线程模型。 Redis基础组建结构 Redis网络层基础组件主要包括四个部分&a…

acm是什么?你准备好去打了吗?(未完结)

1.引言2.acm究竟是什么&#xff1f;3.acm的时间安排4.acm该如何准备1.引言 作为一个零基础的小白&#xff0c;acm这条路走的并不顺畅&#xff0c;接触的信息很少&#xff0c;以至于在这条道路上走了不少弯路&#xff0c;浪费了大量的时间&#xff0c;现在也快要退役的阶段&…

Linux基础-软件包管理器RPM与yum

该文章主要为完成实训任务&#xff0c;详细实现过程及结果见【参考文章】 参考文章&#xff1a;https://howard2005.blog.csdn.net/article/details/127131286?spm1001.2014.3001.5502 文章目录一、使用RPM软件包管理器1. RPM安装软件包2. RPM更新与升级软件包3. RPM查询软件包…

Qt-Web混合开发-Qt读写Json数据(5)

Qt-Web混合开发-Qt使用内置json库读写json示例&#x1f34f; 文章目录Qt-Web混合开发-Qt使用内置json库读写json示例&#x1f34f;1、概述&#x1f353;2、实现效果&#x1f345;3、实现功能&#x1f95d;4、关键代码&#x1f33d;5、源代码&#x1f346;更多精彩内容&#x1f…

面试怎么回答MySQL索引问题,看这里

前言 小A在宿舍里跟哥们开五黑打排位中&#xff0c;突然收到女神小美的消息&#xff1a;“小A&#xff0c;我今天面试碰到索引问题了&#xff0c;我没回答好”。小A顾不上游戏抓紧回复到&#xff1a;“到你宿舍某某咖啡店吧&#xff0c;我帮你一起看下”。 小A抓紧时间换了衣…

物联公司网页设计制作 简单静态HTML网页作品 静态企业网页作业成品 学生网站模板

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

Linux系统部署

Linux系统部署 下载vmware centos7 xshell6 xftp6新建虚拟机&#xff0c;注意设置网络连接&#xff0c;设置登录名&#xff1a;root,密码&#xff1a;root,等待登录&#xff0c;输入用户名和密码&#xff08;注意密码输入不显示&#xff09;登录成功&#xff0c;执行命令Ifc…

【网管日记】MySQL主从复制

MySQL主从复制 基本介绍 MySQL 主从复制是一个异步的复制过程&#xff0c;底层是基于 Mysql 数据库自带的 二进制日志 功能。 一台或多台 MySQL 数据库&#xff08;slave&#xff0c;即 从库 &#xff09;从另一台 MySQL 数据库&#xff08; master&#xff0c;即 主库 &…

餐饮后台管理系统

一、项目介绍&#xff1a; 用于每天的菜品数据分析&#xff0c;客户的管理&#xff0c;员工的管理&#xff0c;查看订单信息&#xff0c;菜品的添加或者下架管理 二、项目使用技术栈&#xff1a; vue2全家桶、element-ui、axios、js、es6、echarts 三、主页效果图&#xff…

pytorch深度学习实战一书,tensorboard可视化踩坑

书评&踩坑[TOC](书评&踩坑) 提示&#xff1a;纯个人观点&#xff0c;仅供参考前言一、源码学习&#xff0c;又是版本问题&#xff08;省略内心独白...&#xff09;二、步骤1.安装tensorflow2.思考&#xff0c;看代码&#xff0c;看书求证总结提示&#xff1a;纯个人观点…

卧兔CEO胡煜受邀参加2022世界直播电商大会

首届全球数字贸易博览会于12月11日在国际博览中心盛大开幕。在这个国家级、全球性、专业性的舞台上&#xff0c;“2022世界直播电商大会”作为分论坛&#xff0c;精彩启幕。 “2022世界直播电商大会”由浙江省人民政府和商务部联合主办&#xff0c;杭州市人民政府和浙江省商务…

借款久期还款久期 简述

借款久期&还款久期 简述 在工作的时候&#xff0c;在资产使用遇到三个指标&#xff0c;分别是生息资产、借款久期、还款久期&#xff0c;有点不清楚其中的含义&#xff0c;查阅相关资料后做个简短的总结&#xff0c;可能有错&#xff0c;先放这。 1 久期 久期&#xff0…

【STM32】GPIO的工作原理和配置

目录一、GPIO是什么&#xff1f;二、GPIO的8种工作模式1. 浮空输入模式&#xff08;GPIO_Mode_IN_FLOATING&#xff09;2. 上拉输入模式&#xff08;GPIO_Mode_IPU&#xff09;3. 下拉输入模式&#xff08;GPIO_Mode_IPD&#xff09;4. 模拟输入模式&#xff08;GPIO_Mode_AIN&…