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