消息队列遥测传输 (MQTT) 协议是一种应用层协议。应用层提供终端节点(物联网设备)和网络之间的接口。对于计算机、笔记本电脑和移动设备,应用层通常由浏览器实现。在物联网设备的情况下,应用层可以通过运行的操作系统(如果嵌入式操作系统正在运行)或固件来实现。
在计算世界中,最常见和无处不在的应用层协议是超文本传输协议 (HTTP)。HTTP 协议专为客户端和服务器之间的通信而设计。该协议使用请求/响应方法,当客户端需要来自服务器的数据时,它向服务器发送请求消息,服务器返回响应消息。HTTP适用于只有一端可以开始数据通信的场合。即客户端发起数据请求,服务器响应。该协议旨在为计算机呈现应用层实现。它仍然可以被 IOT 设备使用,但是,具有受限资源的 IOT 应用程序面临 HTTP 协议的限制。
首先,如前所述,HTTP 是为单向通信而设计的,其中 from-one-way 意味着数据通信只能从一侧发起。服务器无法自行启动与客户端设备的通信。其次,许多,事实上,大多数物联网应用程序需要在有限的网络带宽上运行。物联网设备本身的板载 RAM 和 ROM 有限,计算资源也有限。它们由电池供电,因此需要低功率运行。他们还需要以小代码片段的形式传输或通信数据,尽管带宽和机载资源有限,这些代码片段仍可以安全地传输到另一端。数据虽然体积小,但不仅必须可靠地通信,而且还必须实时通信。
因此,为了满足物联网系统的特定要求,设计了 MQTT 等协议。MQTT 由 Andy Stanford-Clark (IBM) 和 Arlen Nipper 于 1999 年设计,用于通过卫星连接石油管道遥测系统。
MQTT 是一种协议或一组规则,用于设备到设备 (D2D) 通信,以将数据从一个客户端远程交换到另一个客户端。它涉及通过称为 MQTT 代理或服务器的中间组件在全球网络上进行设备到设备或机器到机器的通信。MQTT 的设计方式使客户端和服务器都可以相互通信。使用MQTT协议,任何一端都可以发起数据通信。
在 MQTT 协议中,请求数据的设备称为订阅者,提供数据的设备称为发布者。这是一个轻量级的发布/订阅协议,其中每个单独的 MQTT 客户端都连接到 MQTT 代理,以便与其他 MQTT 客户端通信。物联网设备可以配置为发布者、订阅者或两者。它需要使用 MQTT 代理配置为发布者、订阅者或两者。它是一种面向消息的协议,其中客户端以具有特定主题的消息形式发送和接收数据。任何发布者或订阅者都只能通过代理通过网络进行通信。它们中的任何一个都可以通过代理连接来发起数据通信。就像发布者可以在需要时向代理提供数据,订阅者也可以在需要时请求数据。任何一端发起的数据通信都是实时进行的。因此,在代理的帮助下,可以通过网络进行双向通信。
此外,MQTT 适用于资源受限和功率受限的设备。尽管网络带宽有限,该协议旨在以可靠和实时的方式传达小代码足迹。没有 MQTT 也可以使用 IoT 应用程序,但是当资源受限的 IoT 设备必须在有限的带宽上进行双向通信时,MQTT 提供了优于通用计算机网络应用层协议的架构优势。
发布者和订阅者也可以在协议栈中完全解耦。该协议是在TCP/IP协议栈之上开发的,提供物联网设备之间的远程通信。该协议栈提供设备之间的无损、有序、双向连接。由于物联网中的设备更加分散,代码占用空间更小且带宽有限,像 MQTT 这样的小型代码占用空间解决方案正在成为市场上不断增长的协议。
之所以说MQTT是轻量级协议,是因为该协议的报文开销极小。最小的数据包只有 2 个字节的开销。这种小的传输开销有助于减少网络流量。
MQTT架构
MQTT 使用发布/订阅模型,这实际上需要使用 Central Broker 或 Server。它也称为客户端/服务器模型。MQTT 中主要有两个客户端——一个充当发布者,另一个充当订阅者。Publisher 客户端由 Payload 和 Topic 组成。发布者客户端将消息或有效负载发布到特定主题(比如 X)到 MQTT 代理,订阅者客户端从 MQTT 代理订阅特定主题(如 X)并接收消息并执行相应操作。
为了理解用于 D2D 通信的 MQTT 架构,理解一些与之相关的术语很重要。这些条款如下——
1)有效载荷——有效载荷是客户端(发布者)可能想要发送和共享的实际消息。可以使用 MQTT 协议发送的最大有效负载大小限制为 268、435、456 字节,一个数据包最大为 256 MB。最大大小受 MQTT 规范限制。
2)主题——主题是虚拟通道,用于定义发送数据的路径。根据 MQTT 规范,主题的最大长度可以为 65535 字节。主题由发布者创建并与消息一起发送给代理,然后订阅者可以订阅这些主题。只要主题名称符合标准,它就会被经纪人接受。
MQTT 客户端不使用手机号码或电子邮件地址等地址。这意味着客户端不需要向其他客户端提及这些地址。他们不使用主机地址和目标地址,而是使用主题。主题是 UTF-8(编码方案)字符串,代理使用它来为每个连接的客户端过滤消息。一个主题由一个或多个主题级别组成。每个主题级别由正斜杠分隔。该主题是非常轻量级的字符串。
例如,作为 UTF-8 字符串的主题如下所示 –
My_home/first_floor/dining_room/temperature
My_home/first_floor/dining_room/temperature
印度/德里/India_gate/湿度
在这两个示例中,主题都用于定义消息的路径。在第一个示例中,显示消息(温度)将发送到位于家中一楼的餐厅。主题区分大小写,这意味着 My_home/first_floor 将不同于 My_Home/first_floor。所以在代码中写题目一定要慎重。
从以下教程中了解有关主题的更多信息 –
MQTT 主题和最佳实践
3) MQTT Broker – broker 或 server 主要负责接收来自发布者客户端的所有消息并进行过滤。它决定哪个订阅者对其感兴趣,然后将消息发送给那些订阅的客户端。MQTT 代理用作接收和传输数据的中介。MQTT 代理是此发布/订阅协议的核心。MQTT 代理可以处理多达数千个并发连接的设备。经纪人应该负责客户的身份验证和授权,重要的是,经纪人应该是抗故障的。
4) MQTT 发布者——注册为发布者的 MQTT 客户端向 MQTT 代理发送负载。例如,温度传感器可以是协议中的发布者类型客户端。它可以将温度消息发送到与相关主题对应的代理,消息被包装在有效负载中。
5) MQTT 订阅者——注册为订阅者的 MQTT 客户端从代理请求关于主题的消息(数据)。例如,移动设备可能会请求来自代理的应用程序显示温度消息。
MQTT方法
MQTT 定义了指示要在设备上执行的所需操作的方法。和HTTP协议中有GET、POST、PUT、DELETE方法一样,MQTT协议中有以下方法——
1) CONNECT
2) CONNACK
3) PUBLISH
4) PUBACK
5)PUBREC
6) PUBREL
7) PUBCOMP
8) SUBSCRIBE
9) SUBACK
10) UNSUBSCRIBE
11) UNSUBACK
12) PINGREQ
13) PINGRESP
14) DISCONNECT
CONNECT –为了在代理和客户端之间建立连接,客户端向代理发送一个 CONNECT 数据包。CONNECT 数据包帮助客户端连接到代理并开始其余的通信。CONNECT 数据包包含一个或多个编码字段,如客户端的客户端标识符、遗嘱主题、遗嘱消息、用户名、密码等。CONNECT 数据包包含一个 2 字节的固定报头、一个可变报头(包含协议 名称、协议级别,连接标志和保持活动状态)和有效负载。
连接数据包中的输入参数如下 -
void connect(char *ClientIdentifier, char UserNameFlag, char PasswordFlag, char *UserName, char *Password, char CleanSession, char WillFlag, char WillQoS , char WillRetain, char *WillTopic, char *WillMessage);
有效负载包含以下字段,这些字段必须作为连接函数中的参数传递 –
图 1:列出 MQTT 命令及其功能的表格
图 2:列出 MQTT 命令及其功能的表格
建立连接并传输 CONNECT 数据包后,客户端可以将 OnConnect 数据包发送到 MQTT 代理。OnConnect 数据包设置在回调函数中,这意味着只要建立 MQTT 连接,就会调用此函数。在这个OnConnect回调函数中,客户端可以调用发布和订阅函数(根据客户端的需要)。每当建立 MQTT 连接时,MQTT 发布者客户端将自动发布具有特定主题的消息到 MQTT 代理,并自动订阅该主题。
CONNACK –此数据包由服务器发送到客户端以响应来自客户端的 CONNECT 数据包。数据包包含一个固定的 2 字节报头和一个可变报头。可变标头包含连接确认标志和连接返回代码。此数据包没有负载。连接返回代码可以如下 -
图 3:表格列出连接返回代码
PUBLISH——此数据包由客户端发送到服务器或服务器发送到客户端以传输应用程序消息。数据包包含一个 2 字节的固定报头、一个可变报头和一个有效负载。固定标头包含 MQTT 控制数据包类型的标志、DUP 标志、QoS 级别和 RETAIN 标志。可变标头包含主题名称和数据包标识符。有效负载包含必须发布的应用程序消息。有效载荷 中数据的内容和格式始终是特定于应用程序的。
Publish 数据包中的输入参数如下:
void publish(char DUP, char Qos , char RETAIN, unsigned intMessageID, char *Topic, char *Message);
PUBLISH 函数中的输入参数应该如下:
图 4:在 PUBLISH 函数中列出输入参数的表格
PUBACK –如果 QoS 级别为 1 以响应 PUBLISH 数据包,则此数据包由客户端发送到服务器或服务器发送到客户端。它包含一个 2 字节的固定标头和一个可变标头。此数据包中没有有效载荷。可变标头包含数据包标识符字节。
PUBREC – 如果 QoS 级别为 2 以响应 PUBLISH 数据包,则此数据包由客户端发送到服务器或服务器发送到客户端。它是 QoS 2 协议交换的第二个数据包。它包含一个 2 字节的固定标头和一个可变标头。此数据包中没有有效负载。可变标头包含数据包标识符字节。
PUBREL –如果 QoS 级别为 2 以响应 PUBLISH 数据包,则此数据包由客户端 发送到服务器或服务器发送到客户端。它是 QoS 2 协议交换的第三个数据包。它包含一个 2 字节的固定标头和一个可变标头。此数据包中没有有效载荷。可变标头包含数据包标识符字节。
PUBCOMP –此数据包是为响应 PUBREL 数据包而发送的。它是 QoS 2 协议交换的第四个也是最后一个数据包。它包含一个 2 字节的固定标头和一个可变标头。此数据包中没有有效载荷。可变标头包含数据包标识符字节。
订阅 -此数据包由客户端发送到服务器。它包含一个 2 字节的固定标头、可变标头和一个有效负载。它包含一个主题过滤器列表,指示客户想要订阅的主题。SUBSCRIBE 数据包负载中的主题过滤器必须是 UTF-8 编码的字符串。服务器应支持包含通配符的主题过滤器。如果它选择不支持包含通配符的主题过滤器,它必须拒绝过滤器包含通配符的任何订阅请求。每个过滤器后跟一个称为请求 QoS 的字节。订阅数据包中的输入参数如下 -
void subscribe(char DUP, unsigned intMessageID, char *SubTopic, char SubQoS);
SUBSCRIBE 函数中的输入参数应如下所示 –
图 5:表格列出了 SUBSCRIBE 函数中的输入参数
它仅用于 QoS 级别大于 0 的消息(SUBSCRIBE 消息在 QoS=1 时)
SubTopic 需要订阅的Topic Name。SubQoS 客户端希望接收消息的 QoS 级别。可能的值为 0、1 和 2,分别对应 QoS 级别 0、1 和 2。默认值为 0。
连接后,MQTT客户端自动发布和订阅主题和消息,它们可以向 MQTT 代理发送OnMessage数据包。OnMessage 数据包也设置在一个回调函数中。当从另一个发布者客户端接收到订阅主题的消息时调用此函数。在这个函数中,他们可以调用自定义代码,以便执行某些活动。例如,Client-01 正在 MQTT 代理上发布主题为“Device/LED”的消息“ON”,而 client-02 订阅了主题“Device/LED”。每当消息到达 client-02 时,client-02 都可以基于该消息执行一些任务,比如它可以点亮与其连接的 LED。
OnMessage 回调函数包括以下参数 –
void OnMessage(char *Topic, intTopicLength, char *Message, intMessageLength)
OnMessage 函数中的输入参数应如下所示 –
图 6:表格列出 OnMessage 函数中的输入参数
SUBACK –此数据包由服务器发送给客户端,以确认接收和处理 SUBSCRIBE 数据包。它包含一个固定的 2 字节标头、一个可变标头和一个有效负载。可变标头包含数据包标识符字节。有效负载包含一个返回码列表,它指定在订阅请求的每个订阅中授予的最大 QoS 级别。返回代码可以如下 -
图 7:SUBACK 数据包返回码列表
UNSUBSCRIBE –如果 MQTT 客户端想要取消订阅特定主题,客户端必须向代理发送UNSUBCRIBE数据包。数据包包含一个 2 字节的固定报头、一个可变报头和一个有效负载。可变标头包含数据包标识符字节。有效负载包含客户端希望取消订阅的主题过滤器列表。UNSUBSCRIBE 数据包中的主题过滤器必须是 UTF-8 编码的字符串。一个 UNSUBSCRIBE 数据包的有效载荷必须包含至少一个主题过滤器。没有有效负载的 UNSUBSCRIBE 数据包是违反协议的。可以通过调用取消订阅函数来发送数据包。这个取消订阅功能将帮助 MQTT 客户端取消订阅他们之前订阅的主题。
Unsubscribe 函数的输入参数 包括:
void unsubscribe(char DUP, unsigned intMessageID, char *SubTopic);
UNSUBACK –这是由服务器发送给客户端以确认收到 UNSUBSCRIBE 数据包。它包含一个 2 字节的固定标头和一个可变标头。此数据包中没有有效负载。可变标头包含数据包标识符字节。
PINGREQ——客户端也有保活功能。保持活动功能确保连接仍然打开,并且 MQTT 代理和 MQTT 客户端相互连接。保持活动时间是客户端和代理可以相互连接的最长时间(以秒为单位),即使它们没有相互交换数据也是如此。MQTT 规范说明如下:
客户端有责任确保发送的控制包之间的间隔不超过Keep Alive值。在没有发送任何其他控制包的情况下,客户端必须发送一个 PINGREQ 包。
这意味着,只要两个设备正在相互交换信息并且保持活动时间间隔没有超过所需的限制,就不需要发送额外的消息来检查连接是否仍然打开。但是当客户端停止交换它们的数据并且也超过了保持连接的时间间隔时,MQTT 客户端需要向 MQTT 代理发送 PINREQ 消息以确保连接,MQTT 代理将响应 PINRESP 以确保 MQTT 客户端已连接。
PINGREQ 数据包仅包含一个 2 字节的固定标头。此数据包中没有可变标头或有效负载。
PINGRESP –此数据包由服务器发送给客户端以响应 PINGREQ 数据包。它表示服务器处于活动状态。它只包含一个 2 字节的固定标头。此数据包中没有可变标头或有效负载。
DISCONNECT –如果客户端想要与 MQTT 代理断开连接,则它必须向代理发送 DISCONNECT 数据包。数据包仅包含一个 2 字节的固定标头。此数据包中没有可变标头或有效负载。它可以通过调用断开连接函数来发送。断开连接功能应具有以下参数 -
无效断开连接(无效);
MQTT 协议如何工作?
在 MQTT 中,设备充当客户端,服务器或代理充当具有自己的 SSID 和密码的访问点。MQTT 服务器持续侦听来自客户端的连接。客户之间不直接交谈或相互了解。他们通过 MQTT 代理相互通信。
假设有两个客户端——Client-01 和 Client-02。client-01 充当发布者客户端,client-02 充当订阅者客户端。发布者客户端向 MQTT 代理发布两件事——有效负载(实际消息)和主题(虚拟通道),订阅者客户端从 MQTT 代理订阅主题。发布者客户端和订阅者客户端都首先连接到 MQTT 代理,以便它们可以开始相互通信。每当客户端发起与 MQTT 代理的连接时,都需要通过其唯一 ID 进行连接。
接下来,发布者客户端将服务质量级别(QoS 0,1 或 2)的主题注册到 MQTT 代理,订阅者客户端从 MQTT 代理订阅服务质量级别的主题。MQTT 代理有足够的存储空间用于设备注册表。它通过唯一的 ID 来识别设备。现在,订阅者客户端持续侦听来自 MQTT 代理的关于特定主题的消息。发布者客户端将主题上的消息发布到 MQTT broker,根据发布者客户端的 QoS 级别,消息到达 MQTT broker,MQTT broker 决定该主题是否被任何客户端订阅。订阅者客户端已订阅主题,因此 MQTT 代理将消息传递给订阅者客户端,并取决于订阅者端的 QoS 级别,
发布者客户端也可以同时充当订阅者客户端,反之亦然。上面讨论的整个工作也可以反向实施。以这种方式,管理使用 MQTT 协议的设备到设备的通信。
图 8: 显示 MQTT 协议架构的图像
MQTT 的主要特点–
1. 轻量级消息队列和传输协议,提供一对多的消息分发和应用程序的解耦。
2. 基于消息的异步通信模型。
3. 对于低网络带宽应用,它具有低开销(2 字节标头)。
4.它基于发布/订阅(Pub-Sub)模型。
5. 通过主题(消息队列)实现数据生产者(发布者)和数据消费者(订阅者)的解耦。
6. 这是一个简单的协议,旨在实现低复杂度、低功耗和低占用空间(更少空间)。
7. 它在面向连接的传输 (TCP) 上运行。它可以与 6LoWPAN(TCP 标头压缩)结合使用。例如无线传感器网络。
MQTT 的局限性
每个协议都有一些优点和一些缺点。MQTT 协议也有一些缺点如下 –
1. 它仅适用于需要低带宽、高延迟、数据限制和脆弱连接的受限网络。
2.如果存在不支持 TCP/IP 堆栈的无线传感器网络,则 MQTT 对无线传感器网络没有用处。在这种情况下,应该使用 MQTT-SN。MQTT-SN 是 MQTT 的修改版本,专为没有 TCP/IP 堆栈的低功耗无线传感器网络而设计。