零基础入门学用物联网(ESP8266) 第二部分 MQTT基础篇(一)
参考教程:https://www.bilibili.com/video/BV1L7411c7jw/?spm_id_from=333.1387.favlist.content.click
一、概述
1、MQTT协议的地位
(1)MQTT协议是一个客户端服务端架构的发布/订阅模式的消息传输协议,它的设计思想是轻巧、开放、简单、规范,易于实现,这些特点使得它对很多场景来说都是很好的选择。
(2)与HTTP之类的协议相比,MQTT协议在通过网络传输数据时表现出众,该协议的一个重要特点是易于在客户端实现,因此,MQTT协议成为了当今世界上最受欢迎的物联网协议,它已广泛应用于车联网、智能家居、即时聊天应用和工业互联网等领域。
(3)目前通过MQTT协议连接的设备已经过亿,这些都得益于MQTT协议为设备提供了稳定、可靠、易用的通信基础。
(4)MQTT协议的特点:易于实现;数据传输的服务质量可控;占用带宽小;传输数据内容不可预知;设备连接状态可知。
2、OASIS标准与MQTT协议版本
(1)2014年10月29日,MQTT成为OASIS(结构化信息标准促进组织)正式批准的通讯标准。OASIS是一个推进电子商务标准的发展、融合与采纳的非盈利性国际化组织,相比其它组织,OASIS形成了Web服务标准的同时也提出了安全的电子商务标准,同时在针对公众领域和特定应用市场的标准化方面也付出很多的努力。自1993年成立开始,OASIS已经发展成为了由来自100多个国家的600多家组织、企业。简言之,由众多业内专家组成的OASIS愿意为MQTT背书,足见该协议在物联网领域的重要性。
(2)MQTT协议版本:
①截至2025年,MQTT主流版本有两个,分别是MQTT3.1.1和MQTT5,MQTT3.1.1是在2014年10月发布的,而MQTT5是在2019年3月发布的。本教程将以MQTT3.1.1作为终点讲解。
②MQTT5在MQTT3.1.1的基础上进行了升级,因此MQTT5是完全兼容MQTT3.1.1的。MQTT5在MQTT3.1.1的基础上添加了更多的功能,补充完善MQTT协议。
二、MQTT协议工作机理
1、MQTT协议中的角色
(1)MQTT服务端:
①MQTT服务端通常是一台服务器,它是MQTT信息传输的枢纽,负责将MQTT客户端发送来的信息传递给其它MQTT客户端。
②MQTT服务端负责管理MQTT客户端,确保MQTT客户端之间的通讯顺畅,保证MQTT消息得以正确接收和准确投递。
(2)MQTT客户端:
①MQTT客户端可以向服务端发布信息,也可以从服务端收取信息。
②MQTT客户端发送信息的行为,可称为“发布”信息;而MQTT客户端要想从MQTT服务端收取信息,首先要向MQTT服务端“订阅”信息。
2、服务端通过MQTT主题控制客户端之间的通讯
(1)每个信息都是带有“主题”的,MQTT客户端可订阅某主题的信息,MQTT服务端收到该主题的信息后,会发给订阅了该主题信息的MQTT客户端。
(2)MQTT客户端在通讯时,往往角色不是单一的,针对不同主题,它既可以作为信息发布者,同时也可以作为信息订阅者。为了更好地理解服务端如何通过MQTT主题控制客户端之间的通讯,以下给出两个实例分析:
①实例1:手机和电脑获取汽车的速度。

[1]该实例中一共有三个MQTT客户端,它们分别是汽车、手机和电脑。
[2]手机和电脑作为MQTT客户端,它们想要获取汽车的速度,首先需要向MQTT服务端订阅主题——“汽车速度”,接下来,当汽车向MQTT服务端的“汽车速度”主题发布信息后,MQTT服务端就会检查有哪些客户端订阅了“汽车速度”这一主题的信息,它发现订阅了该主题的MQTT客户端有一部手机和一台电脑,于是就会将刚刚收到的“汽车速度”信息转发给订阅了该主题的手机和电脑MQTT客户端。
②实例2:手机和电脑控制汽车的空调温度。

[1]该实例中一共有三个MQTT客户端,它们分别是汽车、手机和电脑。
[2]手机和电脑作为MQTT客户端,它们想要控制汽车的空调温度,首先汽车需要向MQTT服务端订阅主题——“空调温度”,接下来,当手机或电脑向MQTT服务端的“空调温度”主题发布信息后,MQTT服务端就会检查有哪些客户端订阅了“空调温度”这一主题的信息,它发现订阅了该主题的MQTT客户端有一台汽车,于是就会将刚刚收到的“空调温度”信息转发给订阅了该主题的汽车MQTT客户端。
(4)假设没有MQTT服务端,所有客户端之间自行传递信息,那么可能会面临算力不足的问题。比如有114514个客户端同时向一个客户端订阅了某主题的信息,这个客户端要想把信息发布给订阅了该信息的客户端,需要发送114514次,而这个客户端本身可能还有更重要的任务需要消耗算力,显而易见,有一个MQTT服务端作为“中转”,很大程度上解放了需要发布信息的客户端。
3、MQTT协议发布/订阅特性
(1)相互可独立:MQTT客户端是一个独立的个体,它们无需了解彼此的存在,依然可以实现信息交流。
比如以上实例中,汽车客户端在发布“汽车速度”信息时,汽车客户端本身可以完全不知道有多少个MQTT客户端订阅了“汽车速度”这一主题,而订阅了“汽车速度”主题的手机和电脑客户端也完全不知道彼此的存在
只要有MQTT客户端订阅了“汽车速度”主题,MQTT服务端就会在每次收到新信息时,将信息发送给订阅了“汽车速度”主题的MQTT客户端
(2)空间可分离:MQTT客户端之间通讯的必要条件是,它们连接到了同一个MQTT通讯网络,这个网络可以是互联网或者局域网,只要客户端联网,无论它们彼此的距离有多远,都可以实现彼此间的通讯交流。
(3)时间可异步:MQTT客户端在发送和接收信息时无需同步,这一特点对物联网设备尤为重要。
有时物联网设备会发生意外离线的情况,比如以上实例中,汽车在行驶过程可能会突然进入隧道,这时汽车可能会被迫断开与MQTT服务端的连接,假设此时手机客户端向汽车客户端所订阅的“空调温度”主题发布了信息,而汽车恰恰不在线,这时MQTT服务端可以将“空调温度”主题的新信息保存,待汽车再次上线后,MQTT服务端再将“空调温度”信息推送给汽车
三、连接MQTT服务端
1、MQTT客户端连接服务端的步骤
(1)MQTT客户端向服务端发送连接请求,该请求实际上是一个包含有连接请求信息的数据包(或者说报文),其官方名称为CONNECT。

(2)MQTT服务端收到客户端连接请求后,向客户端发送连接确认,该确认也是一个数据包(或者说报文),其官方名称为CONNACK。

2、CONNECT报文
(1)下图所示的是CONNECT报文示例。

(2)CONNECT报文(数据包)中包含有多个信息,上图左侧栏中的内容是CONNECT报文所包含的信息名称,右侧是信息的具体内容(内容仅是示例)。需要说明的是,CONNECT报文中有些信息是可选的,也就是说,它们不一定存在于所有CONNECT报文中,下面先介绍其中三个必选参数。
①clientId:MQTT客户端的ID。
MQTT客户端在请求连接MQTT服务端时,需要告知服务器自己的ID(或者说名字),以便服务器对多个MQTT客户端进行区分,由此也引出一条规则,对于同一个MQTT服务端,连接它的客户端的clientId是不能发生重复的

MQTT客户端是一个抽象的概念,它并不完全等于一个实体,比如一部电脑,它与MQTT服务端1连接,发布主题为A的信息,同时它还能与MQTT服务端2连接,订阅主题为B的信息,与不同的MQTT服务端连接时,clientId是可以不同的(但不是必须不同)

②cleanSession:标识MQTT客户端是否是重要客户端,是则为false,否则为true。
MQTT客户端与MQTT服务端的连接可能不是非常稳定,而在不稳定的网络环境下,要想保证所有信息传输都能够做到准确无误,这是非常困难的,因此,需要根据MQTT客户端对系统运行的重要性来区别对待
有些MQTT客户端对整个系统运行起着关键作用,这些MQTT客户端一定要准确无误地收到MQTT服务端发来的报文,比如一辆自动驾驶汽车的导航系统,假如这个导航系统错过了MQTT服务端发来的报文,可能会导致交通事故甚至人员伤亡,因此,即使网络不是非常稳定,仍然要求汽车导航系统一定要准确无误地收到MQTT服务端所发来的报文
但是有些MQTT客户端对整个系统运行并不是很重要,比如同样是自动驾驶汽车,它的音乐播放系统如果没有及时收到MQTT服务端发来的音乐播放报文,这对驾驶系统来说影响不大
为了保证重要的MQTT报文可以被MQTT客户端准确无误的收到,在MQTT服务端向MQTT客户端发送报文后,MQTT客户端需要向服务端返回一个确认报文,如果MQTT服务端没有收到MQTT客户端返回的确认报文,那么MQTT服务端就会认为刚刚发送给MQTT客户端的报文没有被准确无误地送达,在这种情况下,MQTT服务端将会执行以下两个操作:
[1]将尚未被MQTT客户端确认的报文保存起来
[2]再次尝试向MQTT客户端发送报文,并且再次等待MQTT客户端发来确认信息
③KeepAlive:心跳时间间隔,单位为s。
MQTT服务端要求与其连接的MQTT客户端每隔一段时间定时给服务器发送心跳消息,以让服务器确定客户端与其的连接保持,无异常断开
3、CONNACK报文
(1)下图所示的是CONNACK报文示例。

(2)CONNACK报文(数据包)中包含有两个信息,上图左侧栏中的内容是CONNACK报文所包含的信息名称,右侧是信息的具体内容(内容仅是示例)。
①returnCode:连接返回码。
当MQTT服务端收到了MQTT客户端的连接请求后,会向客户端发送连接返回码,用以说明连接情况,如果客户端与服务端成功连接,则返回数字“0”,如果未能成功连接,连接返回码将会是一个非零的数值,数值的具体含义见下表:
|
返回码 |
描述 |
|
0 |
成功连接 |
|
1 |
连接被服务端拒绝,原因是不支持客户端的MQTT协议版本 |
|
2 |
连接被服务端拒绝,原因是不支持客户端标识符的编码,可能造成此原因的是客户端标识符编码是UTF-8,但是服务端不允许使用此编码 |
|
3 |
连接被服务端拒绝,原因是服务端不可用,即网络连接已经建立,但MQTT服务不可用 |
|
4 |
连接被服务端拒绝,原因是用户名或密码无效 |
|
5 |
连接被服务端拒绝,原因是客户端未被授权连接到此服务端 |
②sessionPresent:标识MQTT服务端是否保存有未成功发送给MQTT客户端的报文,是则为true,否则为false,该参数主要应用于回复重要MQTT客户端。
当MQTT客户端发送的CONNECT报文中的cleanSession设置为true,在这种情况下,MQTT客户端是不需要MQTT服务端保存任何报文的,那么MQTT服务端发送的确认连接CONNACK报文中,sessionPresent肯定是false
当MQTT客户端发送的CONNECT报文中的cleanSession设置为false时,MQTT客户端是要求MQTT服务端保存报文的,在这种情况下,如果MQTT服务端的确保存了没有收到MQTT客户端接收确认的报文信息,那么sessionPresent为true,否则为false
简言之,CONNACK报文的sessionPresent与CONNECT报文的cleanSession相互配合,其作用是MQTT客户端发送连接请求时,MQTT服务端告知MQTT客户端有没有保存报文信息,这个被MQTT服务端保存的报文信息是来自于上一次MQTT客户端连接时,MQTT服务端曾经发送此报文给MQTT客户端,但是发送后没有收到MQTT客户端的接收确认
更多推荐
所有评论(0)