MQTT设计与实现

目录

前言

一、MQtt简介

二、MQTT代理

1.Mqtt代理(Broker)简介

2.开源MQTT代理对比

三、搭建开源Mqtt Broker

01.开源MQTT代理1:Mosquitto

1.安装Mosquitto Broker:

02.开源MQTT代理2:EMQX Broker

四、MQTT客户端设计

1、功能接口分析

2、在Qt中MQTT客户端(C++)的设计实现

2.1、QT 部署官方MQTT模块

2.2、具体实现Demo

待更新:

在Linux中MQTT客户端(C)的设计与实现

在STM32中MQTT客户端(C)的设计与实现



前言

MQTT协议是应用广泛的物联网通讯协议,在物联网应用中非常重要。此文是本人从零开始,经过查阅学习相关资料的总结。本文主要包含四个部分: 一是Mqtt协议的简介,此部分介绍了mqtt模型等;二是Mqtt Broker的介绍;三是Mqtt 客户端的设计与实现,此部分包含C++(在Qt中,利用Qt库实现);C(在linux环境下,利用paho接口实现) ; 四是关于MQTT的一些个人总结。


一、MQtt简介

        MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议)是IBM开发的一个物联网通讯协议,OASIS(结构化信息标准促进组织)已宣布MQTT协议作为其新兴的物联网消息传递协议的首选。在MQTT的官方网站上,定义MQTT是一种machine-to-machine (M2M)设备之间通信的物联网互联协议,是一种基于发布/订阅(publish/subscribe)模式的“轻量级”通讯协议。作为一种低开销、低带宽占用的即时通讯协议,使其在物联网、小型设备、移动应用等方面有较广泛的应用。

        MQTT协议中有三种身份:发布者(Publish)、代理(Broker)(服务器)、订阅者(Subscribe)。其中,消息的发布者和订阅者都是客户端,消息代理是MQTT服务器,消息发布者可以同时是订阅者。

        在项目实际应用中,包含以下三个角色参与通信:

(1)MQTT代理服务程序,负责接收、存储、转发MQTT消息;

(2)MQTT客户端,一般情况下指的是手机APP程序,为用户提供一个交互界面,负责发布控制命令或查询设备状态信息等;

(3)后台服务端,指的是后台管理系统,负责与数据库交互,为网关和移动终端提供数据服务;实际上后台服务端在整个系统中也是一个MQTT客户端

MQTT传输的消息分为主题(Topic)和负载(payload)两部分:

Topic,可以理解为消息的类型,订阅者订阅(Subscribe)后,就会收到该主题的消息内容(payload)。

payload,可以理解为消息的内容,是指订阅者具体要使用的内容,对应我们的通信协议的消息包。

二、MQTT代理


1.Mqtt代理(Broker)简介

MQTT服务器以称为“消息代理”(Broker),可以是一个应用程序或一台设备。它是位于消息发布者和订阅者之间,它可以:

(1)接受来自客户的网络连接;

(2)接受客户发布的应用信息;

(3)处理来自客户端的订阅和退订请求;

(4)向订阅的客户转发应用程序消息。

2.开源MQTT代理对比

物联网行业里可选的MQTT Broker有很多,除了经典的Mosquitto和AWS、Azure,百度云、阿里云、IBM等几个提供物联网MQTT接入服务的产品外,可用于商业生产的MQTT Broker还有多款。

本文选取了几个热门开源的 MQTT Broker,其中部分项目提供商业支持,做简单选型对比。

对比项目3.EMQHiveMQVerneMQActiveMQMosquitto
License开源+商业版开源+商业版开源+商业版开源开源
公司/社区EMQHiveMQVerenMQApache 基金会Eclipse 基金会
开源协议Apache License 2.0Apache License 2.0Apache License 2.0Apache License 2.0EPL/EDL licensed
开发团队杭州映云科技有限公司dc-square 股份有限公司,德国Octavo Labs AG,瑞士Apache 项目维护者Eclipse 开源社区
开发语言ErlangJavaErlangJavaC
项目历史2012年开始开源,2016年开始商业化2013 年成立,一直以闭源方式向客户提供软件,2019 年开源提供基于开源的商业化定制服务2004 由 LogicBlaze 创建;原本规划的 ActiveMQ 的下一代开源项目 Apollo 已经不活动(4年没有代码更新)
集群架构支持仅企业版支持支持不支持(有伪集群实现)
系统部署物理机、虚拟机、K8S物理机、虚拟机、K8S物理机、虚拟机、K8S物理机、虚拟机、容器物理机、虚拟机、容器
支持协议MQTT、CoAP、MQTT-SN、WebSocket、TCP、UDP、LwM2MMQTTMQTTJMS、Openwire、Stomp、AMQP、MQTT、WebSocket XMPPMQTT、WebSocket
系统性能单机性能较高,单机支持百万级并发,集群支持千万级并发集群支持千万级并发集群支持百万级并发支持集群单机10W
MQTTv3.1,v3.1.1,v5.0v3.1,v3.1.1,v5.0v3.1,v3.1.1,v5.0v3.1v3.1,v3.1.1,v5.0
边缘计算EMQ X Edge 支持树莓派,ARM 等架构,支持数据同步到云服务 Azure IoT Hub AWS不支持不支持不支持支持(自身比较轻量)
安全与认证TLS/DTLS、X.509证书、JWT、OAuth2.0、应用协议(ID/用户名/密码)、数据库与接口形式的认证与 ACL 功能(LDAP、DB、HTTP)TLS/DTLS、X.509证书、JWT、OAuth2.0、应用协议(ID/用户名/密码)、配置文件形式的认证与 ACL 功能TLS/DTLS、X.509证书、配置文件形式的认证与 ACL 功能、数据库形式的认证与 ACL 功能,但支持数据库较少LDAP (JAAS)、Apache Shiro等待
运行持久化支持将消息数据持久化至外部数据库如 Redis、MySQL、PostgreSQL、MongoDB、Cassa、Dynamo 等,需企业版,开源版宕机则丢失开源企业均支持本地持久化,采用磁盘系统,支持备份,导出备份支持持久化至 Google LevelDBAMQ、KahaDB、JDBC、LevelDB等待
扩展方式Webhook、Trigger、Plugin 等,支持 Erlang 与 Lua、Java、Python 扩展开发,支持 Webhook 开发,侵入性不强Trigger、Plugin 等,使用 Java 技术栈开发,提供方便开发的 SDKTrigger、Plugin 等,支持 Erlang 与 Lua 扩展开发Java 扩展等待
数据存储企业版适配数据库:Redis、Mysql、PostgreSQL、MongoDB、Cassandra、OpenTSDB、TimescaleDB、InfluxDB 适配消息队列:Kakfa、RabbitMQ、Pulsar 桥接模式:支持桥接至标准 MQTT 协议消息服务
开源版支持 HTTP 将数据同步、存储
适配数据库:无,提供 Java SDK 开发进行适配
消息队列:Kafka 桥接模式:支持桥接至标准 MQTT 协议消息服务
适配数据库:无,提供 Erlang 和 Lua 扩展开发 适配消息队列:无 桥接模式:支持桥接至标准 MQTT 协议消息服务适配数据库:JDBC、KahaDB、LevelDB 适配消息队列:无 桥接模式:支持通过 JMS 桥接等待
管理监控支持可视化的 Dashboard,实现集群与节点的统一集中管理 支持第三方监控工具 Prometheus ,提供可视化 Grafana 界面模板支持可视化的 HiveMQ Control Center,实现集群与节点统一管理 支持第三方监控工具 Prometheus ,可提供可视化 Grafana 界面 支持 InfluxDB 监控内置简单状态管理可视化界面 支持第三方监控工具 Prometheus ,可提供可视化 Grafana 界面支持可视化的监控界面 支持第三方监控工具 Prometheus ,可提供可视化 Grafana 界面通过 MQTT 订阅系统主题
规则引擎支持规则引擎,基于 SQL 的规则引擎给予 Broker 超越一般消息中间件的能力。除了在接受转发消息之外,规则引擎还可以解析消息的格式(企业版)。
规则引擎由消息的订阅,发布,确认的事件触发,根据消息的负载来执行相应的动作,降低应用开发的复杂度。
不支持不支持不支持不支持
开发集成支持通过 REST API 进行常用的业务管理操作如: 调整设置、获取 Broker 状态信息、进行消息发布、代理订阅与取消订阅、断开指定客户端、查看客户端列表、规则引擎管理、插件管理,提供 Java SDK、Python SDK 直接编码处理业务逻辑无,提供 Java SDK 在应用系统在编码的层面操作进程,非常灵活但耦合性高提供少量 REST API,用于监控与状态管理、客户端管理等。 缺乏代理订阅、业务管理等功能和 API提供少量队列管理 REST API等待
适用场景优势在于高并发连接与高吞吐消息的服务能力,以及物联网协议栈支持的完整性;扩展能力较强,无需过多开发有一定高并发连接与高吞吐消息的服务能力,物联网协议栈的完整性较弱仅支持 MQTT 协议;缺乏开箱即用的功能插件,功能必须编码使用基础的并发连接与高吞吐消息的服务能力,物联网协议栈的完整性较弱仅支持 MQTT 协议;扩展能力较差,基础的业务组件支持度不够,商业成熟度不足客户量较少,缺乏开箱即用的功能插件  核心是消息队列系统,主要用于支持异构应用之间的消息通信,比如用于企业消息总线等;后面支持了部分物联网协议。ActiveMQ 比较适合系统既要支持传统的异构应用之间需要通信,也需要支持小型物联网接入支持的用户。轻量简便的 MQTT Broker,工控、网关或小规模接入项目

三、搭建开源Mqtt Broker

01.开源MQTT代理1:Mosquitto

MQTT Broker 即MQTT 消息服务器,实际上是一个TCP服务端。在这里我们选择搭建轻量的mosquitto服务器作为演示,快速搭建一个MQTT Broker,使初步接触的同学们有一个快速的了解。我使用的是腾讯云的轻量型云服务器,系统版本为:Ubuntu 20.04

参考文章:https://blog.csdn.net/qq_28632173/article/details/84933527

1.安装Mosquitto Broker:

1.安装mosquitto
apt-get install mosquitto

2.查看状态
service mosquitto status

3.配置文件详解(mosquitto安装后,其配置文件在 /etc/mosquitte/conf.d目录下
# =================================================================
# General configuration
# =================================================================

# 客户端心跳的间隔时间
#retry_interval 20

# 系统状态的刷新时间
#sys_interval 10

# 系统资源的回收时间,0表示尽快处理
#store_clean_interval 10

# 服务进程的PID
#pid_file /var/run/mosquitto.pid

# 服务进程的系统用户
#user mosquitto

# 客户端心跳消息的最大并发数
#max_inflight_messages 10

# 客户端心跳消息缓存队列
#max_queued_messages 100

# 用于设置客户端长连接的过期时间,默认永不过期
#persistent_client_expiration

# =================================================================
# Default listener
# =================================================================

# 服务绑定的IP地址
#bind_address

# 服务绑定的端口号
#port 1883

# 允许的最大连接数,-1表示没有限制
#max_connections -1

# cafile:CA证书文件
# capath:CA证书目录
# certfile:PEM证书文件
# keyfile:PEM密钥文件
#cafile
#capath
#certfile
#keyfile

# 必须提供证书以保证数据安全性
#require_certificate false

# 若require_certificate值为true,use_identity_as_username也必须为true
#use_identity_as_username false

# 启用PSK(Pre-shared-key)支持
#psk_hint

# SSL/TSL加密算法,可以使用“openssl ciphers”命令获取
# as the output of that command.
#ciphers

# =================================================================
# Persistence
# =================================================================

# 消息自动保存的间隔时间
#autosave_interval 1800

# 消息自动保存功能的开关
#autosave_on_changes false

# 持久化功能的开关
persistence true

# 持久化DB文件
#persistence_file mosquitto.db

# 持久化DB文件目录
#persistence_location /var/lib/mosquitto/

# =================================================================
# Logging
# =================================================================

# 4种日志模式:stdout、stderr、syslog、topic
# none 则表示不记日志,此配置可以提升些许性能
log_dest none

# 选择日志的级别(可设置多项)
#log_type error
#log_type warning
#log_type notice
#log_type information

# 是否记录客户端连接信息
#connection_messages true

# 是否记录日志时间
#log_timestamp true

# =================================================================
# Security
# =================================================================

# 客户端ID的前缀限制,可用于保证安全性
#clientid_prefixes

# 允许匿名用户
#allow_anonymous true

# 用户/密码文件,默认格式:username:password
#password_file

# PSK格式密码文件,默认格式:identity:key
#psk_file

# pattern write sensor/%u/data
# ACL权限配置,常用语法如下:
# 用户限制:user <username>
# 话题限制:topic [read|write] <topic>
# 正则限制:pattern write sensor/%u/data
#acl_file

# =================================================================
# Bridges
# =================================================================

# 允许服务之间使用“桥接”模式(可用于分布式部署)
#connection <name>
#address <host>[:<port>]
#topic <topic> [[[out | in | both] qos-level] local-prefix remote-prefix]

# 设置桥接的客户端ID
#clientid

# 桥接断开时,是否清除远程服务器中的消息
#cleansession false

# 是否发布桥接的状态信息
#notifications true

# 设置桥接模式下,消息将会发布到的话题地址
# $SYS/broker/connection/<clientid>/state
#notification_topic

# 设置桥接的keepalive数值
#keepalive_interval 60

# 桥接模式,目前有三种:automatic、lazy、once
#start_type automatic

# 桥接模式automatic的超时时间
#restart_timeout 30

# 桥接模式lazy的超时时间
#idle_timeout 60

# 桥接客户端的用户名
#username

# 桥接客户端的密码
#password

# bridge_cafile:桥接客户端的CA证书文件
# bridge_capath:桥接客户端的CA证书目录
# bridge_certfile:桥接客户端的PEM证书文件
# bridge_keyfile:桥接客户端的PEM密钥文件
#bridge_cafile
#bridge_capath
#bridge_certfile
#bridge_keyfile

# 自己的配置可以放到以下目录中
include_dir /etc/mosquitto/conf.d

02.开源MQTT代理2:EMQX Broker

        Emqx broker是本次主要介绍的一款国产MQTT代理。按照网上所说,性能上EMQX单机版支持百万并发,集群支持千万并发,性能上完胜其他mqtt服务器。抛开性能不说,由于EMQX国产,支持国产,相对其他代理来说,EMQX具有丰富的中文文档资料,查阅方便,EMQX官网也有简洁的MQTT相关知识的介绍,对于初学者绝对是一个很好的选择。

        这里先给出EMQX官方文档地址:产品概览 | EMQX 文档

        安装部署的说明直接根据官方的文档引导进行即可。

四、MQTT客户端设计

1、功能接口分析

连接、发布、订阅、服务质量、ping(后续会更新,其实也是一些知识点的搬运)

2、在Qt中MQTT客户端(C++)的设计实现

2.1、QT 部署官方MQTT模块

在Qt Creator中,默认是没有部署Mqtt模块的,在使用QT编程之前,先把mqtt 模块部署到开发环境当中。参考博文:Qt开发技术:mqtt介绍、QtMqtt编译和开发环境搭建_长沙红胖子-CSDN博客

  • 下载

Qt官方在github上提供了源代码,地址:https://github.com/qt/qtmqtt.选择对应的版本下载

  • 编译源码

打开源码文件,双击.pro打开工程文件,选择release编译。

编译这个源码需要安装perl,否则会报错:perl 不是内部或外部命令,也不是可运行的程序。

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

安装完Perl后会自动写入环境变量, 这时候再次编译(Release模式)QtMqtt源码,编译完成后得到以下文件:

  • 将Mqtt模块布署到QT环境中

2.2、具体实现Demo

  • MqttDemo.pro

QT       += core gui mqtt

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++11

# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    main.cpp \
    mainwindow.cpp

HEADERS += \
    mainwindow.h

FORMS += \
    mainwindow.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
  • mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QtMqtt/QtMqttClient>
#include <QDateTime>
#include <QMessageBox>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

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

private slots:
    void updateLogStateChange();

    void brokerDisconnected();

    void message_rcv(const QByteArray &message, const QMqttTopicName &topic);

    void on_pushButton_clicked();

    void on_pushButton_2_clicked();

private:
    Ui::MainWindow *ui;
    QMqttClient *mqtt_client;


};
#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);

    mqtt_client = new QMqttClient(this);

    connect(mqtt_client, &QMqttClient::stateChanged, this, &MainWindow::updateLogStateChange);    //状态已更改
    connect(mqtt_client, &QMqttClient::disconnected, this, &MainWindow::brokerDisconnected);      //与代理断开
    connect(mqtt_client, &QMqttClient::messageReceived, this, &MainWindow::message_rcv);          //接收消息
}

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


void MainWindow::on_pushButton_clicked()
{
    QString hostName = ui->lineEdit->text();
    quint16 hostPort = ui->lineEdit_2->text().toInt();
    QString userName = ui->lineEdit_3->text();
    QString userPasswd = ui->lineEdit_4->text();

    mqtt_client->setHostname(hostName);
    mqtt_client->setPort(hostPort);
    mqtt_client->setUsername(userName);
    mqtt_client->setPassword(userPasswd);

    if (mqtt_client->state() == QMqttClient::Disconnected)
    {
       mqtt_client->connectToHost();
       ui->pushButton->setText("断开");
    }
    else
    {
        mqtt_client->disconnectFromHost();
    }
}


/*更新连接状态*/
void MainWindow::updateLogStateChange()
{
    QString connect_state;
    if(mqtt_client->state() == QMqttClient::Connecting)
    {
        connect_state = "连接中...";
    }
    if(mqtt_client->state() == QMqttClient::Connected)
    {
        connect_state = "已连接";

        QMessageBox::information(this,tr("提示"), "已连接服务器");
    }
    else if(mqtt_client->state() == QMqttClient::Disconnected)
    {
       connect_state = "未连接";

       QMessageBox::information(this,tr("提示"), tr("mqtt服务器已断开!"));
    }

    ui->textBrowser->append(connect_state);

}


/*与代理断开连接*/
void MainWindow::brokerDisconnected()
{
    ui->pushButton->setText(tr("连接"));
    //ui->lw_subscription_topic->clear();         //清理连接
}

/*接收服务器发送来的消息的槽函数*/
void MainWindow::message_rcv(const QByteArray &message, const QMqttTopicName &topic)
{
    ui->textBrowser->append("收到主题: " + topic.name() + "\n内容:\n " + message);
}


void MainWindow::on_pushButton_2_clicked()
{
    QString topic = ui->lineEdit_5->text();
    if(topic == "")
    {
        QMessageBox::critical(this,tr("Error"),tr("请输入订阅主题"));
        return;
    }

    auto subscription = mqtt_client->subscribe(topic);
    if (!subscription)
    {
        QMessageBox::critical(this, QLatin1String("Error"), tr("订阅失败!请查看是否连接?"));
        return;
    }

    ui->textBrowser->append("已订阅:" + topic);
}

void MainWindow::on_pushButton_3_clicked()
{
    QString topic = ui->lineEdit_6->text();
    QString payload = ui->textEdit->toPlainText();
    quint8 Qos = static_cast<quint8>(ui->spinBox->value());

    if(topic == "")
    {
        QMessageBox::critical(this, QLatin1String("Error"), tr("请输入发布的主题"));
        return;
    }
    if (mqtt_client->publish(topic,payload.toUtf8(),Qos) == -1)
    {
        QMessageBox::critical(this, QLatin1String("Error"), QString(" 发布消息失败!"));
        return;
    }
    else
    {
        ui->textBrowser->append("发布主题:"+ topic + "\n内容: \n" + payload);
    }


}
  • 实现效果

链接:https://pan.baidu.com/s/1ukITOBic5HPq75qTVZNfdw 
提取码:21l2

待更新:

在Linux中MQTT客户端(C)的设计与实现

在STM32中MQTT客户端(C)的设计与实现


 

参考文章:MQTT Broker 比较与选型——开源与商业服务器/服务对比 | MindSpark

               如何在Ubuntu 18.04上安装和保护Mosquitto MQTT Messaging Broker - 云+社区 - 腾讯云

MQTT协议从服务端到客户端详解 - 简书

程序源码:

  • 8
    点赞
  • 71
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于MQTT协议的即时通信系统设计实现可以分为以下几个步骤: 首先,我们需要搭建一个MQTT消息代理服务器。这个服务器将负责接收所有的消息,并将其分发给相应的订阅者。可以选择使用已有的MQTT代理服务器,比如Mosquitto或Eclipse Paho等,也可以根据自己的需求自行实现。 其次,我们需要为用户提供一个基于MQTT协议的客户端应用程序。用户可以通过这个应用程序发送和接收即时消息。这个应用程序需要支持用户的登录和注销、消息的发送和接收等基本功能。可以使用现有的MQTT客户端库进行开发,比如Paho MQTTMQTT.js等。 接下来,需要设计实现消息的发布和订阅机制。用户可以选择订阅感兴趣的主题,当有新的消息发布到这个主题时,他们将收到相应的通知。可以使用MQTT的订阅/发布模式来实现这个机制。 同时,需要考虑系统的安全性和可靠性。可以使用TLS/SSL协议来进行消息的加密和身份验证,以确保消息的机密性和完整性。另外,可以使用MQTT提供的QoS服务来保证消息的可靠传输。 最后,可以根据实际需求扩展系统的功能。比如可以增加群组聊天、文件传输、在线状态管理等功能。这些功能可以通过订阅/发布模式和MQTT消息协议来实现。 在系统实施后,还需要进行测试和优化。可以使用MQTT消息代理服务器的负载测试工具来模拟大量用户同时使用系统,并监控系统的性能和稳定性。通过对系统进行优化,可以提高其并发处理能力和响应速度。 总之,基于MQTT协议的即时通信系统设计实现需要搭建MQTT消息代理服务器、开发MQTT客户端应用程序、设计消息的发布和订阅机制、保证系统的安全性和可靠性,并根据需求扩展功能。通过不断的测试和优化,可以提高系统的性能和稳定性,为用户提供高质量的即时通信服务。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值