参考博客:https://www.jianshu.com/p/ecde412d2eeb
简介
MQTT 全称为 Message Queuing Telemetry Transport(消息队列遥测传输)是一种基于发布/订阅范式的轻量级消息协议,由 IBM 发布。
- MQTT 可以被解释为一种低开销,低带宽占用的即时通讯协议,可以用极少的代码和带宽的为连接远程设备提供实时可靠的消息服务,它适用于硬件性能低下的远程设备以及网络状况糟糕的环境下。因此 MQTT 协议在 IoT(Internet of Things,物联网),小型设备应用,移动应用等方面有较广泛的应用。
- IoT 设备要运作,就必须连接到互联网,设备才能相互协作,以及与后端服务协同工作。而互联网的基础网络协议是 TCP/IP,MQTT 协议是基于 TCP/IP 协议栈而构建的,因此它已经慢慢的已经成为了 IoT 通讯的标准。
1、基本特点
1.1 MQTT 是一种发布/订阅传输协议
基本原理和实现如下:
1.2 使用 TCP 提供网络连接,提供有序、无损、双向连接
MQTT 是一种连接协议,它指定了如何组织数据字节 并通过 TCP 网络传输它们。设备联网,也需要连接到互联网中。在大万维的世界中,TCP 如同汽车,有轮子就能用来运输数据,MQTT 就像是交通规则。
在网络模型中,TCP是传输层协议,而 MQTT是在应用层,在 TCP 的上层,因此MQTT 也是基于TCP而构建的,提高了可靠性。
1.3 对负载内容屏蔽的消息传输
可以对消息订阅者所接受到的内容有所屏蔽。
1.4 具体有三种消息发布的服务质量
- 至多一次:消息发布完全依赖底层 TCP 网络。会发生消息丢失或重复。这一级别可用于如下情况,环境传感器数据,丢失一次读记录无所谓,因为不久后还会有第二次发送。
- 至少一次:确保消息到达,但消息重复可能会发生。
- 只有一次:确保消息到达一次。这一级别可用于如下情况,在计费系统中,消息重复或丢失 会导致不正确的结果。
1.5 小型传输,开销小
小型传输,开销小,固定长度的头部是 2 字节,协议交换最小化,以降低网络流量。
整体上,协议可拆分为:固定头部+可变头部+消息体,这就是为什么在介绍里说它非常适合 “在物联网领域,传感器与服务器的通信,信息的收集”。
1.6 使用 Last Will:遗言机制
使用 Last Will 和 Testament 特性通知有关各方客户端异常中断的机制;
-
Last Will:即遗言机制,用于通知同一主题下的其他设备,发送遗言的设备已经断开了连接。
-
Testament:遗嘱机制,功能类似于Last Will。
2、基本概念
2.1 MQTT 客户端
一个使用 MQTT 协议的设备、应用程序等,它总是建立 到服务器的网络连接。
- 可以发布信息,其他客户端 可以订阅该信息
- 订阅其它客户端 发布的消息
- 退订或删除 应用程序的消息
- 断开与服务器连接
2.2 MQTT 服务器(Broker)
MQTT 服务器以称为 Broker(消息代理),以是一个应用程序或一台设备。它是位于 消息发布者 和 订阅者 之间。
- 接受 来自客户端 的网络连接
- 接受 客户端 发布的应用信息
- 处理来自客户端的 订阅和退订请求
- 向订阅的客户,转发应用程序消息
2.3 主题(Topic)
连接到一个应用程序消息的标签,该标签与服务器的订阅相匹配。
服务器会将消息 发送给订阅所匹配标签的 每个客户端。
-
要订阅的主题。一个主题可以有多个级别,级别之间用斜杠字符分隔。例如,/world 和 emq/emqtt/emqx 是有效的主题。
-
订阅者的 Topic name 支持通配符#和+ :
(1)#
支持一个主题内任意级别话题
(2)+
只匹配一个主题级别的通配符 -
客户端成功订阅某个主题后,代理会返回一条 SUBACK 消息,其中包含一个或多个 returnCode 参数
2.4 主题筛选器(Topic Filter)
一个对 主题名 通配符 筛选器,在订阅表达式中使用,表示订阅所匹配到的多个主题。
2.5 QoS(消息传递的服务质量水平)
服务质量,标志表明此主题范围内的消息传送到客户端所需的一致程度。
- 值 0:不可靠,消息基本上仅传送一次。如果当时客户端不可用,则会丢失该消息。
- 值 1:消息应传送 至少1次。
- 值 2:消息 仅传送1次。
2.6 会话(Session)
每个客户端与服务器建立连接后就是一个会话,客户端和服务器之间有状态交互。
会话存在于一个网络之间,也可能在客户端和服务器之间跨越多个连续的网络连接。
2.7 订阅(Subscription)
订阅包含主题筛选器(Topic Filter)和最大服务质量(QoS)。订阅会与一个会话(Session)关联。一个会话可以包含多个订阅。每一个会话中的每个订阅都有一个不同的主题筛选器。
- 客户端在成功建立TCP连接之后,发送CONNECT消息,在得到服务器端授权允许建立彼此连接的CONNACK消息之后,客户端会发送SUBSCRIBE消息,订阅感兴趣的Topic主题列表(至少一个主题)
- 订阅的主题名称采用UTF-8编码,然后紧跟着对应的QoS值
2.8 发布(publish)
控制报文是指从客户端向服务端或者服务端向客户端传输一个应用消息,MQTT 客户端发送消息请求,发送完成后返回应用程序线程
- 比如安卓的推送服务,还有一些即时通信软件 如微信等也是采用的推送技术。
2.9 负载(Payload)
消息订阅者 所具体接收的内容。
3、简单示例
MQTT 协议主要是根据以下情况设计的:
- M2M(Machine to Machine),机器或设备间端到端通信,比如传感器之间的数据通讯。
- 设备(Machine)中,例如传感器,硬件能力很弱,协议要考虑尽量小的资源消耗,比如计算能力和存储等。
根据 MQTT 的基础了解后并结合简单的架构,在这里做一个简单的示例图,可以更直观的理解MQTT协议的通信模型。
MQTT Broker 就选择 EMQ 作为示范。比如有1个温度传感器(1个Machine),1个移动设备,1个电脑,一个服务器(3个Machine),都可以得到或者显示温度传感器的温度值,需要先通过 MQTT 协议subscribe(订阅)一个比如叫 temperature 的 topic(主题)如下:
图中移动设备,服务器,电脑需要先通过 EMQ subscribe 一个叫 temperature 的 topic,当温度传感器 publish 温度数据,三个设备就可以收到了。
4、进一步了解 MQTT 3
MQTT 3 (当前版本3.1.1)是目前使用的最为广泛的MQTT协议标准。尽管MQTT5标准已经发布,并且带来了一些令人振奋的新特性,但是在整个应用场景上,从后台服务到消息中间件再到客户端SDK等环节上的产品升级并没有都完成,再加上既有部署的维护,业界从版本3到5的过渡可能会持续相当长一段时间,所以,对于刚加入物联网行业的生力军来说,现在来学习MQTT 3依然是一件很有意义的事情。
5、MQTT 协议的工作方式
前面简介中讲到,在一个QMTT协议中有三个角色会参与到整个通信过程,发布者(publisher)、代理(broker)和订阅者(subscriber)。有别于传统的客户端/服务器通讯协议,MQTT协议并不是端到端的,消息传递通过代理,包括会话(session)也不是建立在发布者和订阅者之间,而是建立在端和代理之间。代理解除了发布者和订阅者之间的耦合。
除了发布者和订阅者之间传递普通消息,代理还可以为发布者处理保留消息和遗愿消息,并可以更改服务质量(QoS)等级。
6、MQTT 控制报文格式
MQTT协议工作在TCP之上,端和代理之间通过交换预先定义的控制报文来完成通信。
6.1 MQTT 控制报文的结构
MQTT报文有3个部分组成,并按下表顺序出现:
序号 | 部分 | 描述 |
---|---|---|
1 | 固定报头(Fixed header) | 所有控制报文都包含 |
2 | 可变报头(Variable header) | 部分控制报文包含 |
3 | 有效载荷(Payload) | 部分控制报文包含 |
6.2 固定报头(Fixed header)
每个 MQTT 控制报文都包含一个固定报头。
固定报头的格式:
6.2.1 MQTT 控制报文的类型
位置:第 1 个字节,二进制位 7-4。
表示为 4 位无符号值,这些值的定义如下:
名字 | 值 | 报文流动方向 | 描述 |
---|---|---|---|
Reserved | 0 | 禁止 | 保留 |
CONNECT | 1 | 客户端到服务端 | 客户端请求连接服务端 |
CONNACK | 2 | 服务端到客户端 | 连接报文确认 |
PUBLISH | 3 | 两个方向都允许 | 发布消息 |
PUBACK | 4 | 两个方向都允许 | QoS 1 消息发布收到确认 |
PUBREC | 5 | 两个方向都允许 | 发布收到(保证交付第一步) |
PUBREL | 6 | 两个方向都允许 | 发布释放(保证交付第二步) |
PUBCOMP | 7 | 两个方向都允许 | QoS 2 消息发布完成(保证交互第三步) |
SUBSCRIBE | 8 | 客户端到服务端 | 客户端订阅请求 |
SUBACK | 9 | 服务端到客户端 | 订阅请求报文确认 |
UNSUBSCRIBE | 10 | 客户端到服务端 | 客户端取消订阅请求 |
UNSUBACK | 11 | 服务端到客户端 | 取消订阅报文确认 |
PINGREQ | 12 | 客户端到服务端 | 心跳请求 |
PINGRESP | 13 | 服务端到客户端 | 心跳响应 |
DISCONNECT | 14 | 客户端到服务端 | 客户端断开连接 |
Reserved | 15 | 禁止 | 保留 |
6.2.2 剩余长度
位置:从第 2 个字节开始。
剩余长度(Remaining Length)表示当前报文剩余部分的字节数,包括可变报头和负载的数据。剩余长度不包括用于编码剩余长度字段本身的字节数。
剩余长度字段使用一个变长度编码方案,对小于 128 的值它使用单字节编码。更大的值按下面的方式处理。
低 7 位有效位用于编码数据,最高有效位用于指示是否有更多的字节。因此每个字节可以编码 128 个数值和一个 延续位( continuation bit ) 。剩余长度字段最大 4 个字节。
剩余长度字段的大小:
分别表示(每个字节的低 7 位用于编码数据,最高位是标志位):
1 个字节时,从 0(0x00) 到 127(0x7f)
2 个字节时,从 128(0x80,0x01) 到 16383(0Xff,0x7f)
3 个字节时,从 16384(0x80,0x80,0x01) 到 2097151(0xFF,0xFF,0x7F)
4 个字节时,从 2097152(0x80,0x80,0x80,0x01) 到 268435455(0xFF,0xFF,0xFF,0x7F)