MQTT全称是(Message Queuing Telemetry Transport),即消息队列遥测传输协议
是一种基于发布/订阅(Publish/Subscribe)模式的轻量级通讯协议,并且该协议构建于TCP/IP协议之上,常用于互联网中,轻便
客户端(Client):
代理(Broker):
连接:
发布(Publish):
sensors/temperature/kitchen
。订阅(Subscribe):
消息分发:
断开连接:
MQTT广泛应用于物联网、车联网、智能家居、远程监控和消息推送等场景。其轻量级、低带宽、高效的特性使其特别适合资源受限及网络不稳定的环境。
通过这些组件和操作,MQTT可以实现高效、可靠的消息传递,成为物联网通信中的重要协议。
准备工作:MQTT客户端的交互需要安装MQTT代理,及代理服务器,负责将消息转发。按照好后配置相关,如监听的端口和协议、是否启用消息持久化、日志文件路径等。根据需求修改这些设置,保存配置文件等。这里就不赘述
接下来详细讲解在QT中MQTT的使用:
1.使用官方的MQTT源码,造好的轮子有用就用,官网:https://github.com/emqx/qmqtt
或者这个链接下载: https://pan.baidu.com/s/1oUtl9R628-3cfS-tyL6iEQ?pwd=1234 提取码: 1234
下载完解压:放到程序目录下
我的例子程序结构如下,分为mqtt封装的库,用于发送接收消息,和界面主程序用于控制发送和消息显示
2.写一个例子,这里给关键代码展示
一是连接mqtt,二是推送消息函数,三是接收订阅的消息函数
- void MqttShareHandle::initMqtt()
- {
- if (client) {
- return;
- }
- client.reset(new QMqttClient);
- QObject::connect(client.get(), &QMqttClient::connected, this, &MqttShareHandle::connected);
- QObject::connect(client.get(), &QMqttClient::disconnected, this, &MqttShareHandle::disconnected);
- QObject::connect(client.get(), &QMqttClient::errorChanged, this, &MqttShareHandle::errorChanged);
- QObject::connect(client.get(), &QMqttClient::messageReceived, this,
- [=](const QByteArray &message, const QMqttTopicName &topic) {
- emit messageReceived(message, topic.name());
- });
- QObject::connect(client.get(), &QMqttClient::messageReceived, this,
- [=](const QByteArray &message, const QMqttTopicName &topic) {
- onMessageReceived(message, topic.name());
- });
- }
-
- void MqttShareHandle::connectToHost(const QString &host,
- quint16 port,
- const QString &username,
- const QString &password)
- {
- if (!client || isConnected()) {
- return;
- }
-
- client->setHostname(host);
- client->setPort(port);
- client->setUsername(username);
- client->setPassword(password);
- client->connectToHost();
- }
- //订阅消息
- void MqttShareHandle::subscribeBizTopics()
- {
- //保证消息至少到达一次。
- //较为可靠,适用于大多数需要保证消息到达的场景
- const quint8 qos = 1;
- subscribeTopic(TopicAppEnvData, qos);
- subscribeTopic(TopicAppDeviceStatus, qos);
- subscribeTopic(TopicAppEventNotify, qos);
- }
-
- bool MqttShareHandle::subscribeTopic(const QString &topic, quint8 qos)
- {
- if (!client) {
- return false;
- }
-
- auto subscription = client->subscribe(topic, qos);
- return subscription ? subscription->state() == QMqttSubscription::Subscribed : false;
- }
-
- //推送消息
- bool MqttShareHandle::publishTopic(const QString &topic, const QByteArray &data, quint8 qos, bool retain)
- {
- if (!client) {
- return false;
- }
- emit printMsg(QString("推送消息, topic:%1,data:%2").arg(topic).arg(QString(data)));
- auto ret = client->publish(topic, data, qos, retain);
- return ret != -1;
- }
-
- void MqttShareHandle::onMessageReceived(const QByteArray &message, const QString &topic)
- {
- QJsonParseError error;
- QJsonDocument doc = QJsonDocument::fromJson(message, &error);
- if (error.error != QJsonParseError::NoError) {
- return;
- }
- //QMetaObject::invokeMethod(this, MessageMap.value(topic).toUtf8(), Q_ARG(QByteArray,message));
- emit printMsg(QString("收到消息推送, topic:%1,data:%2").arg(topic).arg(QString(message)));
-
- if(topic == TopicAppEnvData) {
- emit appEnvDataUpdate(message);
- }
- else if(topic == TopicAppEventNotify) {
- emit appEventNotify(message);
- }
- else if(topic == TopicAppDeviceStatus) {
- emit appDeviceStatusUpdate(message);
- }
- }
我的这个例子用了五个主题要演示推送和接收
- // 环境信息更新主题
- QString MqttShareHandle::TopicAppEnvData = "/Topic/EnvData";
- // 设备状态更新主题
- QString MqttShareHandle::TopicAppDeviceStatus = "/Topic/DeviceStatus";
- // 事件通知主题
- QString MqttShareHandle::TopicAppEventNotify = "/Topic/EventNotify";
- //------------------------消息发布(推送)-------------------------
- // 控制设备主题
- QString MqttShareHandle::TopicControlDevice = "/Topic/ControlDevice";
- // 控制门主题(开关门)
- QString MqttShareHandle::TopicControlDoor = "/Topic/ControlDoor";
写了一个demo程序,如下,改程序可以通过mqtt推送开关门控制事件,模拟控制订阅“TopicControlDoor”主题的设备控制开关门,控制订阅TopicControlDevice主题的设备控制开关灯,并且订阅相关设备推送消息的主题,便于接收响应的信息
演示下效果,比较简陋,:
我用这个QT客户端模式外部设备
通过订阅环境主题,事件,设备状态,可以接收设备的相关消息推送
设备也订阅了控门事件,控灯事件。接收到app的推送后,也显示出来,做出相应的处理
通过这个例子,可以认识到,mqtt的通讯方式是一对多,也可以一对一,实现方式也很简单,订阅与发布。
订阅就相当于你关注了一个人,UP主(uploader),他要是发布了动态或者视频等,就会通知你,如果你没有关注那个人,肯定不会接收到通知
发布就反过来,你是UP主,发布的东西只要他人关注了你,就会被通知
这个例子的源码我就放在这里了,有什么不懂的,欢迎评论区交流哈!
链接: https://pan.baidu.com/s/1v_xViXSHoV2QekwdKDq7SA?pwd=6666 提取码: 6666
为什么有了tcp通信后,还要有人写一个mqtt出来呢?
MQTT 采用发布/订阅模式,允许客户端发布消息到主题(Topic),其他客户端可以订阅这些主题来接收消息。这种模式使得消息的传递更加灵活和解耦,客户端之间不需要直接连接,减少了复杂性。
MQTT 协议设计得非常轻量级,适合在带宽有限、网络不稳定的环境中使用,如物联网设备。MQTT 的消息头非常小,最小只有 2 字节,这使得它在低带宽网络中传输效率更高。
MQTT 提供了三种服务质量(QoS)级别:
QoS 0(最多一次,At most once)
特点:
使用场合:
优点:
缺点:
QoS 1(至少一次,At least once)
特点:
使用场合:
优点:
缺点:
QoS 2(只有一次,Exactly once)
特点:
使用场合:
优点:
缺点:
这些 QoS 级别使得 MQTT 能够适应不同的应用场景,确保消息的可靠传输。
MQTT 支持会话保持(Session Persistence),即使在客户端断开连接后,服务器仍然可以保存客户端的订阅信息和未接收的消息,当客户端重新连接时,可以继续接收这些消息。
MQTT 支持遗嘱消息(LWT),客户端可以在连接时设置一个遗嘱消息,当客户端异常断开连接时,服务器会自动发布这个遗嘱消息,通知其他客户端该客户端已经断开连接。
MQTT 支持心跳机制(Keep Alive),客户端可以定期发送 PING 请求,确保连接的活跃性,服务器也可以通过 PING 响应来检测客户端的连接状态。
MQTT 支持 TLS/SSL 加密,确保消息在传输过程中的安全性。此外,MQTT 还支持用户名和密码认证,增加了系统的安全性。
MQTT 的发布/订阅模式和主题(Topic)结构使得系统易于扩展。新的客户端可以轻松地加入系统,订阅感兴趣的主题,而不需要修改现有的客户端或服务器。
MQTT 协议得到了广泛的支持,有大量的客户端库和服务器实现,适用于各种编程语言和平台,如 C、C++、Java、Python、JavaScript 等。
相比于直接使用 TCP,MQTT 提供了更高层次的抽象和功能,使得消息的传递更加灵活、可靠和高效。特别是在物联网和低带宽网络环境中,MQTT 的优势更加明显。