购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

Chapter 3
第3章
MQTT协议基础

MQTT协议是运行在TCP协议栈上的应用层协议,虽然MQTT协议的名称有Message和Queue两个词,但是它并不是像RabbitMQ那样的消息队列,这是初学者最容易搞混的一个问题。与传统的消息队列相比,MQTT协议有以下几点不同。

1)传统消息队列在发送消息前必须先创建相应的队列。在MQTT协议中,不需要预先创建要发布的主题(可订阅的Topic)。

2)传统消息队列中,未被消费的消息会被保存在某个队列中,直到有一个消费者将其消费。在MQTT协议中,如果发布一个没有被任何客户端订阅的消息,这个消息将被直接扔掉。

3)传统消息队列中,一个消息只能被一个客户端获取。在MQTT协议中,一个消息可以被多个订阅者获取,MQTT协议也不支持指定消息被单一的客户端获取。

3.1 MQTT协议的通信模型

就像我们之前提到的,MQTT协议的通信是通过发布/订阅的方式来实现的,消息的发布方和订阅方通过这种方式进行解耦,它们之间没有直接的连接,所以需要一个中间方来对信息进行转发和存储。在MQTT协议里,我们称这个中间方为Broker,称连接到Broker的订阅方和发布方为Client。

一次典型的MQTT协议消息通信流程如图3-1所示。

图3-1 MQTT协议消息通信流程

1)发布方和订阅方都建立了到Broker的TCP连接。

2)订阅方告知Broker它要订阅的消息主题(Topic)。

3)发布方将消息发送到Broker,并指定消息的主题。

4)Broker接收到消息以后,检查都有哪些订阅方订阅了这个主题,然后将消息发送到这些订阅方。

5)订阅方从Broker获取该消息。

6)如果某个订阅方此时处于离线状态,Broker可以先为它保存此条消息,当订阅方下次连接到Broker的时候,再将这条消息发送到订阅方。

在本书的后续部分,我们将发送方称为Publisher,将订阅方称为Subscriber。

3.2 MQTT的不同版本

MQTT协议目前有2个常用版本——3.1.1和5.0,支持和使用最广泛的版本是3.1.1。

2017年8月,OASIS MQTT Technical Committee发布了MQTT 5.0草案。2018年,MQTT 5.0正式发布。MQTT 5.0并未改变MQTT协议通信的架构和流程,而是在3.1.1的基础上推出了一些新特性,用来解决3.1.1版本的缺陷和不足,提供更多功能,方便应用的开发。MQTT 5.0并不向下兼容MQTT 3.1.1。

在后续的章节里,我们将基于MQTT 3.1.1版本来详细讲解MQTT的架构和通信的细节,还会详细地讲解MQTT 5.0的新特性。

3.3 MQTT Client

任何终端,无论是嵌入式设备,还是服务器,只要运行了MQTT协议的库或者代码并连接了MQTT Broker,我们都称其为MQTT Client。Publisher和Subscriber都属于Client。一个Client是Publisher还是Subscriber,只取决于该Client当前的状态——是在发布消息还是在订阅消息。当然,一个Client可以同时是Publisher和Subscriber。

在大多数情况下,我们不需要自己按照MQTT协议规范来实现一个MQTT Client,因为MQTT Client库在很多语言中都有实现,包括Android、Arduino、Ruby、C、C++、C#、Go、iOS、Java、JavaScript以及.NET等。如果你要查看相应语言的库实现,可以查看https://github.com/mqtt/mqtt.github.io/wiki/libraries。图3-2展示了MQTT Client在各个平台上的实现。

图3-2 MQTT Client在各个平台上的实现

在本书中,我们将使用MQTT Client在Node.js上进行代码演示和开发,首先你需要安装Node.js,然后安装对应的MQTT协议包。

之后就可以在代码中使用MQTT Client的相关功能了。

3.4 MQTT Broker

搭建一个完整的MQTT协议环境,除了需要MQTT Client外,我们还需要一个MQTT Broker。如前文所述,Broker负责接收Publisher的消息,并将消息发送给相应的Subscriber,它是整个MQTT协议订阅/发布的核心。

在实际应用中,一个MQTT Broker还应该提供如下功能:

●可以对Client的接入进行授权,并对Client进行权限控制。

●可以横向扩展,比如集群,满足海量的Client接入。

●有较好的扩展性,可以比较方便地接入现有业务系统。

●易于监控,满足高可用性。

下面列举了几个比较常用的MQTT Broker。

(1)Mosquitto

Mosquitto是一款用C语言编写的开源MQTT Broker,单机配置和运行Mosquitto比较简单,官方并没有集群的解决方案。如果要扩展Mosquitto的功能,比如自定义的验证方式,实现过程比较复杂,对接现有的业务系统等也较为复杂,需要对Mosquitto代码比较熟悉。如果只是想搭建一个测试Broker或者单机验证功能的环境,Mosquitto还是比较合适的,但如果想在生产系统中使用,则需要自行解决集群和扩展的问题。

(2)EMQX

EMQX是由我国开发并提供商业支持的MQTT Broker。EMQX同时提供开源社区版和付费企业版。EMQX是用Erlang语言编写的,官方提供集群解决方案,并可以通过编写插件的方式对Broker的功能进行扩展。EMQX的开发者社区比较活跃,青云提供的物联网套件就是基于EMQX的。在生产系统中使用EMQX已经有几年了,EMQX的性能在笔者看来是很不错的,唯一的缺点就是Erlang这门语言比较小众,而且学习曲线较陡,编写插件的时候可能需要重新学习一门语言。第6章会对EMQX进行详细介绍。

(3)HiveMQ

HiveMQ是用Java编写的MQTT Broker,支持集群,同时也可以通过插件的方式对功能进行扩展。Java语言的受众较广,功能扩展相对简单。不过HiveMQ是闭源的,只有付费企业版。

(4)VerneMQ

VerneMQ是开源的、用Erlang编写的MQTT Broker,且由一家位于瑞士的公司提供商业服务。VerneMQ同样支持集群,并可以使用插件的方式对功能进行扩展。

除了上面提到的几个常用的MQTT Broker,你还可以在https://github.com/mqtt/mqtt.github.io/wiki/servers找到更多的MQTT Broker。

除了自建Broker,我们还可以使用前面提到的阿里云、腾讯云、青云之类的云服务商提供的物联网云平台的MQTT协议服务。

如果只是抱着学习或者测试的目的,我们还可以使用一些公共的MQTT Broker,这里我们先使用一个公共的MQTT Broker(mqtt.eclipse.org)讲解和学习MQTT协议,在后面的章节里,再学习如何搭建一个MQTT Broker。

3.5 MQTT协议数据包格式

不同于HTTP,MQTT协议使用的是二进制数据包。MQTT协议的数据包非常简单,一个MQTT协议数据包由固定头(Fix Header)、可变头(Variable Header)、消息体(Payload)这3个部分依次组成。

●固定头:存在于所有的MQTT协议数据包中,用于表示数据包类型及对应标识,表明数据包大小。

●可变头:存在于部分类型的MQTT协议数据包中,具体内容由相应类型的数据包决定。

●消息体:存在于部分MQTT协议数据包中,存储消息的具体数据。

这里我们首先看一下固定头,可变头和消息体将在讲解各种具体类型的MQTT协议数据包的时候详细讨论。

MQTT协议数据包的固定头格式如图3-3所示。

图3-3 MQTT协议数据包的固定头格式

(1)数据包类型

MQTT协议数据包的固定头的第一个字节的高4位用于指定该数据包的类型。MQTT协议数据包类型如表3-1所示。

表3-1 MQTT协议数据包类型

(续)

(2)数据包标识位

MQTT协议数据包的固定头的第一个字节的低4位用于指定数据包的标识位(Flag)。在不同类型的数据包中,标识位的定义是不一样的,每种数据包对应的标识位如表3-2所示。

表3-2 MQTT协议数据包的固定头的标识位含义

注:DUP、QoS、Retain标识的含义将在后文进行详细讲解。

(3)数据包剩余长度

从固定位的第二个字节开始,是用于标识当前数据包剩余长度的字段,剩余长度等于可变头长度加上消息体长度。

这个字段最少为1个字节,最多为4个字节。其中,每一个字节的最高位叫作延续位(Continuation Bit),用于标识在这个字节之后是否还有一个用于表示剩余长度的字节。剩下的低7位用于标识值,范围为0~127。

例如,剩余长度字段的第一个字节的最高位为1,那么意味着剩余长度至少还有1个字节,然后继续读下一个字节,下一个字节的最高位为0,那么剩余长度字段到此为止,一共2个字节。

剩余长度字段可标识的数据包长度如表3-3所示。

表3-3 剩余长度字段可标识的数据包长度

所以,4个字节最多可标识的数据包长度为(0xFF,0xFF,0xFF,0x7F)=268435455字节,即256MB,这是MQTT协议中数据包的最大长度。

3.6 本章小结

本章介绍了MQTT协议的通信模型,以及Client和Broker的概念,同时讲解了MQTT协议数据包的格式。接下来,我们将从建立MQTT协议连接开始,详细讲解MQTT协议的规范以及特性,并辅以实例代码。 lmWdfcZe3XJgAX56ggPaRzHzKq9N19wUv71g4q+1rLUR5VORISySOfsLJNN+jJel

点击中间区域
呼出菜单
上一章
目录
下一章
×