物联网协议之MQTT

news2025/1/10 16:32:44

MQTT

简介

MQTT 可以简单看做一个网络协议,用于机器对机器的通信(与客户端到服务器的传输有点区别)。智能传感器、可穿戴设备和其他物联网(IoT)设备通常必须通过带宽有限资源受限网络传输和接收数据。这些物联网设备使用 MQTT 进行数据传输,因为它易于实施,并且可以有效地传输物联网数据。MQTT 支持设备到云端和云端到设备之间的消息传递。

特点

  1. 轻量级:MQTT协议是一种轻量级的协议,它的开销非常小,可以在低带宽、不稳定的网络环境下运行。
  2. 灵活性:双向通信,MQTT协议支持多种消息传输模式,包括点对点、发布/订阅和请求/响应等模式,可以根据不同的应用场景选择合适的模式。
  3. 可靠性:MQTT协议支持QoS(服务质量)等级,可以确保消息的可靠传输,同时还支持消息持久化和重传机制,保证消息不会丢失。
  4. 易于集成:MQTT协议可以与各种不同的平台和设备集成,包括传感器、嵌入式设备、移动设备和云平台等,可以实现跨平台、跨设备的通信。
  5. 安全性:MQTT协议支持TLS/SSL加密和认证机制,可以保证消息的安全传输和身份验证,防止数据泄露和攻击。

MQTT为什么轻量

从连接角度上看

HTTP:假设有一个传感器设备需要定期向云平台发送数据,数据量很小,只有几个字节,但是设备的网络带宽很低,且网络连接不稳定。如果使用传统的HTTP协议来传输数据,由于HTTP协议的开销较大,每次传输都需要建立TCP连接、发送HTTP头部等操作,会导致网络带宽的浪费和连接的不稳定性

MQTT:而如果使用MQTT协议来传输数据,由于MQTT协议是一种轻量级的协议,它的开销非常小。1.只需要建立一次TCP连接,然后就可以通过MQTT协议来传输数据,不需要每次都重新建立连接和发送头部信息,可以大大减少网络带宽的浪费和连接的不稳定性。2.同时,MQTT协议还支持QoS等级,可以确保数据的可靠传输,即使网络连接不稳定,也可以保证数据不会丢失。

MQTT的长连接机制和HTTP的Keep-Alive机制有所不同,HTTP中客户端和服务器之间的数据传输是同步的。MQTT客户端和服务器之间的数据传输是异步的,客户端可以发送多个消息,服务器可以异步地接收和处理这些消息。需要注意的是,MQTT协议的长连接机制需要客户端和服务器之间的协作,客户端需要定期发送心跳包来保持连接,服务器需要及时响应心跳包,以保证连接的稳定性。同时,长时间的连接也会占用服务器的资源,因此需要合理设置连接的超时时间和心跳包的发送间隔。

从报文角度上看

  1. MQTT协议的头部信息

MQTT协议的头部信息非常简单,只需要几个字节就可以表示。MQTT协议的头部信息包括以下几个字段:

  • 固定头部:包含消息类型、QoS等级、保留标志等信息,共1个字节。
  • 可变头部:包含消息标识符、主题名等信息,长度不固定。
  • 消息体:包含消息的实际内容,长度不固定。

例如:假设有一个MQTT客户端需要向服务器发送一条消息,消息内容为"Hello, MQTT!“,主题名为"test”,QoS等级为1。

固定头部:0x32(消息类型为Publish,QoS等级为1,保留标志为0)

可变头部:0x00 0x04(主题名长度为4)

主题名:0x74 0x65 0x73 0x74(主题名为"test")

消息标识符:0x00 0x01(消息标识符为1)

消息体:0x48 0x65 0x6C 0x6C 0x6F 2C 0x20 0x4D 0x51 0x54 0x54 0x21(消息内容为"Hello, MQTT!")

  1. HTTP协议的头部信息

HTTP协议的头部信息相对复杂,包含了很多字段,主要用于描述请求或响应的相关信息。HTTP协议的头部信息包括以下几个部分:

  • 请求行:包含请求方法、请求URL和HTTP协议版本等信息。
  • 请求头部:包含请求的附加信息,如请求头部字段、Cookie等。
  • 空行:用于分隔请求头部和请求正文。
  • 响应行:包含HTTP协议版本、状态码和状态描述等信息。
  • 响应头部:包含响应的附加信息,如响应头部字段、Cookie等。
  • 空行:用于分隔响应头部和响应正文。
  • 响应正文:包含响应的实际内容,长度不固定。

例如:

假设有一个HTTP客户端需要向服务器发送一个GET请求,请求URL为"http://www.example.com/index.html",请求头部包含"User-Agent"和"Accept-Language"字段。那么该请求的HTTP协议头部信息如下:

请求行:GET /index.html HTTP/1.1

请求头部: User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 Accept-Language: en-US,en;q=0.8

空行:

响应行:HTTP/1.1 200 OK

响应头部: Content-Type: text/html; charset=UTF-8 Content-Length: 1234

空行:

响应正文:(省略)

可以对比看出MQTT协议的报文信息都是用十六进制表示,各个请求属性也是这种用二进制的位图去区分,相对HTTP报文都是字符串来说更加的轻量,节省传输资源。

从数据类型上看

HTTP协议的数据格式是文本格式,即使用ASCII码表示的文本字符串,而MQTT协议的数据格式是二进制格式,即使用字节流表示的二进制数据。

使用二进制表示的话,每个字节可以表示多个0或1,而文本字符串使用字符编码方式表示,每个字符通常需要使用多个字节来表示,例如UTF-8编码中的中文字符需要使用3个字节来表示,这就导致了文本字符串的数据大小通常比二进制数据大。

同时二进制数据通常可以使用压缩算法进行压缩,压缩后的数据大小更小,传输效率更高。而文本字符串的压缩效果通常不如二进制数据,因为文本字符串中的字符通常是不规则的,难以进行有效的压缩。

总的来说,使用二进制数据传输可以减少数据的大小,提高传输效率,因为二进制数据使用二进制编码方式表示,可以更紧凑地表示数据,同时可以使用更高效的压缩算法进行压缩,而且二进制数据通常使用二进制传输方式,传输效率更高。与之相比,文本字符串的数据大小通常较大,压缩效果较差,传输效率较低。

三种服务质量

MQTT的三种服务质量及实现原理:

https://www.emqx.com/zh/blog/introduction-to-mqtt-qos

QoS 0:最多一次传递

在QoS 0级别下,发布者只需将消息发送给MQTT代理,代理会将消息发送给订阅者,但不会保证消息是否到达订阅者。这种级别的实现非常简单,因为不需要进行确认或重传,所以消息传递的延迟和带宽占用都很低。

通常选择使用 QoS 0 传输一些高频且不那么重要的数据,比如传感器数据,周期性更新,即使遗漏几个周期的数据也可以接受。

QoS 1:最少一次传递

发送方发送报文后,需要收到一个ACK报文,才会停止重复发送,否则到了超时时间会重传报文。这里其实是涉及到两次网络传输(一次发送报文消息、一次接收方发送ACK报文信息)

在QoS 1级别下,发布者将消息发送给MQTT代理,代理会将消息发送给订阅者,并等待订阅者的确认。如果代理没有收到确认,它会重新发送消息,直到收到确认为止。这种级别的实现需要进行确认和重传,所以消息传递的延迟和带宽占用都比QoS 0高。

QoS1在协议层面上无法避免消息重复的情况,因此在我们的报文内容里面通常加上报文的唯一id,在应用层通过id去对消息去重是最常规的处理方法。

QoS 2:恰好一次传递

前提:MQTT识别报文是通过一个Packet ID来识别是不是重复信息。Qos1收到两条相同Packet ID报文的消息是没办法知道这是重复的信息,还是两条不同的消息只是用的同一个ID的情况,因此Qos1是存在重复消息的问题。QoS2会用更加复杂的交互逻辑来确保消息不会重复。

发送方发送完报文,需要等待收到接收方发送PUBREC报文(在这期间还可以超时重发这个报文),等到收到PUBREC报文后,发送方会继续发送PUBREL (Publish Release)报文,此时不能再重发报文了,并且Packet ID也不能使用。等待收到对端回复的 PUBCOMP 报文后,才表示此时Packet ID被释放完成,可以继续使用Packet ID去发送消息。

因此对于接收方以 PUBREL 报文为界限,凡是在 PUBREL 报文之前到达的 PUBLISH 报文,有相同的Packet ID都必然是重复的消息;而凡是在 PUBREL 报文之后到达的 PUBLISH 报文,有相同的Packet ID都必然是全新的消息。

在这里插入图片描述

在QoS 2级别下,发布者将消息发送给MQTT代理,代理会将消息发送给订阅者,并等待订阅者的确认。如果代理没有收到确认,它会重新发送消息,直到收到确认为止。订阅者收到消息后,会发送确认给代理,代理再将确认发送给发布者。如果代理没有收到确认,它会重新发送消息,直到收到确认为止。这种级别的实现需要进行确认、重传和去重,所以消息传递的延迟和带宽占用都比QoS 1更高。

总的来说,QoS级别越高,消息传递的可靠性越高,但延迟和带宽占用也越高。在选择QoS级别时,需要根据应用场景的需求来进行权衡。

在MQTT中,QoS级别是在发布消息时指定的。接收者也可以指定所需的QoS级别。如果发布者和接收者的QoS级别不同,MQTT会自动升级到更高的级别。例如,如果发布者使用QoS 0,而接收者使用QoS 2,MQTT会将消息升级到QoS 2级别。

消息可靠

MQTT还有一个持久会话的功能,对应的是Clean Session(清理会话)选项。当Clean Session = 0,以及QoS为1或着2的时候,加入接收端离线了也会在下次在线时收到断连期间的消息。此时的消息会暂存在我们的MQTT服务器端。

MQTT Broker

MQTT Broker 也称为 MQTT 消息服务器,它可以是运行了 MQTT 消息服务器软件的一台服务器或一个服务器集群。

MQTT Broker 负责接收来自客户端的网络连接,并处理客户端的订阅/取消订阅、消息发布(Publish)请求,同时也会将客户端发布的消息转发给其他订阅者。

在这里插入图片描述

MQTT负载均衡

MQTT通过共享订阅的方式来做订阅端的负载均衡

MQTT使用共享订阅来实现负载均衡的方法如下:

  1. 创建一个共享订阅,多个客户端可以订阅同一个主题。

  2. 在共享订阅中,MQTT服务器将消息平均分配给所有订阅者,以实现负载均衡。

  3. 当一个客户端订阅了共享订阅中的主题时,它将收到一部分消息。

  4. 如果有多个客户端订阅了共享订阅中的主题,它们将共享消息的负载。

  5. 如果一个客户端断开连接,MQTT服务器将重新分配该客户端的负载给其他订阅者。

  6. 使用共享订阅可以提高MQTT服务器的性能和可伸缩性,同时确保消息的可靠传递。

例如实时数据处理:当需要处理大量实时数据时,使用共享订阅可以将数据平均分配给多个订阅者,从而实现负载均衡。

MQTT broker也可以通过集群实现服务器端的负载均衡

多服务器节点集群,且支持节点的自动发现。相对于单服务器,集群能通过多台服务器之间的协作带来以下优势:

  • 高可用性。单台或少量的服务器故障并不会导致整个消息服务中断,其余的正常工作的节点可以继续提供服务;
  • 负载均衡。通过负载均衡机制,集群可以把负载平均的分布在各个节点;
  • 更高的整体性能。相比单机部署,多节点的集群能够成倍的提升整个系统的连接和消息处理能力;
  • 可扩展性。可以通过在集群中添加新节点的方式来完成扩容而无需停机。

MQTT做请求应答模式

MQTT本身是一种发布/订阅模式的通信协议,不直接支持请求/响应模式。但是,可以通过以下方法实现请求/响应模式:

  1. 使用MQTT的QoS(服务质量)机制。将QoS设置为1或2,可以确保消息的可靠传输和确认。在请求消息中设置一个唯一的标识符,然后在响应消息中包含相同的标识符,以便请求方可以识别响应。 2. 使用专门的主题来处理请求和响应。例如,可以使用“request”主题来发送请求消息,然后使用“response”主题来发送响应消息。请求方可以订阅响应主题,以便在收到响应时进行处理。

  2. 使用MQTT的遗嘱消息机制。请求方可以在发送请求消息时设置遗嘱消息,以便在请求方离线或者异常时,服务器可以代替请求方给所有订阅相关主题的客户端发送一个响应消息作为遗嘱消息。

需要注意的是,使用MQTT实现请求/响应模式可能会增加通信的延迟和复杂性。因此,应该根据具体的应用场景和需求来选择合适的通信模式。

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

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

相关文章

更新cuda和 pytorch==1.12.1版本,更新到cuda11.3.1

nvidia-smi 查看gpu支持的最高cuda版本 nvcc -V 查看当前cuda版本 卸载旧版本cuda 除了NVIDIA Geforce、NVIDIA PhysX、NVIDIA图形驱动程序,将电脑中其他NVIDIA开头的全部卸载 安装cuda 下载适合的cuda版本 https://developer.nvidia.com/cuda-toolkit-ar…

基于QT开发的使用OPC_UA与西门子1200,1500系列PLC通信的工业监控Demo

目录 一,总体介绍 二,需要的软件 三,需要的硬件 四,QT程序代码 五,西门子PLC代码 一,总体介绍 先看一下图1-1的QT运行界面图,界面中服务器地址就是OPC_UA服务器地址,整个项目作…

图解LeetCode——19. 删除链表的倒数第 N 个结点

一、题目 给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。 二、示例 2.1> 示例 1: 【输入】head [1,2,3,4,5], n 2 【输出】[1,2,3,5] 2.2> 示例 2: 【输入】head [1], n 1 【输出】[] 2.3> 示例…

数值计算 - 误差的来源

误差的来源是多方面的,但主要来源为:过失误差,描述误差,观测误差,截断误差和舍入误差。 过失误差 过失误差是由设备故障和人为的错误所产生的误差,在由于每个人都有“权利”利用机器进行数值计算,所以在计算…

#include <archive.h>报错

#include <archive.h>报错 archive配置 Linux环境下&#xff0c;在C项目.cpp文件中存在如下语句&#xff0c;导致无法运行~ #include <archive.h> #include <archive_entry.h>由于C编译器默认不包含archive&#xff0c;所以我们需要自行配置。 Libarchiv…

Java 基础--interview经典(个人认为)题目

1&#xff09;多线程中 synchronized 锁升级的原理是什么&#xff1f; synchronized 锁升级原理&#xff1a;在锁对象的对象头里面有一个 threadid 字段&#xff0c;在第一次访问的时候 threadid 为空&#xff0c;jvm 让其持有偏向锁&#xff0c;并将 threadid 设置为其线程 i…

终の序章(一)

前言 写在我大三的最后一次省赛 &#xff0c;也是最后一次比赛 从半年前区域赛的大失利&#xff0c;导致我曾一度放弃算法竞赛和算法训练 新路历程 考虑到前几次的省赛&#xff0c;我们这次采取 稳 的一种方式&#xff0c;因为前几次省赛难度跨度较 大&#xff0c;对于大部…

【牛客网面试必刷TOP101】链表篇(二)

【牛客网面试必刷TOP101】链表篇&#xff08;二&#xff09; 前言刷题网站刷题&#xff01;BM4 合并两个排序的链表思路一&#xff1a;双指针思路二&#xff1a;递归&#xff08;扩展思路&#xff09; BM5 合并k个已排序的链表思路一&#xff1a;归并排序思想 BM6 判断链表中是…

内网渗透(七十九)之 CVE-2021-42287 权限提升漏洞

CVE-2021-42287 权限提升漏洞 漏洞背景 2021年11月9日,微软发布11月份安全补丁更新。在该安全补丁更新中,修复了两个域内权限提升漏洞CVE-2021-42287 、CVE-2021-42278。当时这两个漏洞的利用详情和POC并未公布,因此并未受到太多人关注。 一个月后,国外安全研究员公布了…

[CTF/网络安全] 攻防世界 ics-06 解题详析

[CTF/网络安全] 攻防世界 ics-06 解题详析 姿势&#xff08;Burp爆破&#xff09; 题目描述&#xff1a;云平台报表中心收集了设备管理基础服务的数据&#xff0c;但是数据被删除了&#xff0c;只有一处留下了入侵者的痕迹。 可知&#xff1a;报表中心含有部分数据 仅报表中心…

C++内存管理/函数模板/类模板

一、C内存管理 C中内存基本形式与C语言类似&#xff0c;可以参考下图。 X64环境下总共大小为8G,X86环境下为4G。 1、内核空间&#xff1a;用户不能读写&#xff0c;但要占用一定空间。 2、栈区&#xff1a;以开辟、销毁栈帧形式运行&#xff0c;主要应用于局部变量和函数栈帧…

chatgpt赋能Python-python3_choice

Python3中的choice()函数&#xff1a;一种简单而有趣的随机选择方式 在Python3中&#xff0c;choice()函数是一个常见的随机模块。它允许我们从一个序列中随机选择一个元素。这在程序中经常用于生成一些需要随机展示的数据。本文将介绍Python3中的choice()函数&#xff0c;并探…

00.SpringCloud服务调用方式

服务调用方式 RPC和HTTP 无论是微服务还是SOA&#xff0c;都面临着服务间的远程调用。那么服务间的远程调用方式有哪些呢&#xff1f; 常见的远程调用方式有以下2种&#xff1a; RPC&#xff1a;Remote Produce Call远程过程调用&#xff0c;类似的还有 。自定义数据格式&am…

合合信息亮相CCIG2023:多位大咖共话智能文档未来,文档图像内容安全还面临哪些技术难题?

近日&#xff0c;中国图象图形大会&#xff08;CCIG 2023&#xff09;&#xff08;简称“大会”&#xff09;在苏州圆满落幕。本届大会以“图象图形向未来”为主题&#xff0c;由中国科学技术协会指导&#xff0c;中国图象图形学学会主办&#xff0c;苏州科技大学承办&#xff…

干货 | 利用SPSS进行高级统计第一期(更新)

Hello&#xff0c;大家好&#xff01; 这里是壹脑云科研圈&#xff0c;我是喵君姐姐~ 在之前的文章中&#xff0c;我们以此介绍了如何利用SPSS进行高级统计分析&#xff0c;内容包括&#xff1a; (1)描述性统计表格模板、卡方&T检验、相关&回归分析 (2)中介、多重中…

MD5_buuctf

概念 MD5信息摘要算法&#xff0c;一种被广泛使用的密码散列函数&#xff0c;可以产生出一个128位&#xff08;16字节&#xff09;的散列值&#xff08;hash value&#xff09;&#xff0c;用于确保信息传输完整一致。 MD5算法具有以下特点&#xff1a; 压缩性&#xff1a;任意…

一次失败的面试经历:我只想找个工作,你却看不起我?还用面试题羞辱我...

这段时间都说难找工作&#xff0c;没有面试机会。面对如此严峻的形式&#xff0c;很多软件测试人员都希望能拿一个满意的高薪offer&#xff0c;但是随着招聘职位的不断增多&#xff0c;面试的难度也随之加大&#xff0c;而面试官更是会择优录取 我最近为面试已经焦头烂额了&am…

循坏队列+OJ题之设计循环队列

生命不是要等待风暴过去&#xff0c;而是要学会在风暴中跳舞。 ——卡莉尔吉布朗目录 &#x1f33a;前言&#xff1a; &#x1f341;一.循环队列是什么&#xff1f; &#x1f34f;二.循环队列有什么作用&#xff1f; &#x1f340;三.OJ题之设计循环队列 1…

C++(3):字符串、向量和数组

命名空间的 using 声明 using namespace::name;1.每个名字都需要独立的 using 声明&#xff1b; 2.头文件不应包含 using 声明&#xff1a; 因为头文件的内容会拷贝到所有引用它的文件中去&#xff0c;如果头文件里有某个using声明&#xff0c;那么每个使用了该头文件的文件就…

Apache Kafka - 重识Kafka生产者

文章目录 概述Kafka 生产者Kafka 生产者工作原理如何使用 Kafka 生产者 生产者配置项&#xff08;核心&#xff09;导图总结 概述 Kafka 生产者是 Apache Kafka 中的一个重要组件&#xff0c;它负责将数据发送到 Kafka 集群中。在实时数据处理和流式处理应用程序中&#xff0c…