不论我们使用哪种互联网接入方式,只要我们的设备可以通过 UPD / TCP 通信访问互联网上对应 IP 地址的主机,那么理论上,当设备与云服务器建立 UDP / TCP通信后,只要按照云服务器所规定的的通信协议(数据格式)发送 / 接收消息,我们的设备就能接入云平台,实现物联网。
MQTT介绍
【MQTT】:就是一种通信协议(数据格式协议),百度云、阿里云、腾讯云的物联网组件都支持MQTT协议。
特点:
1 “轻量级”通信协议,实现MQTT开销比较小,无需太多额外的数据 / 成本;
2 基于 TCP / IP 协议,建立TCP连接后,【云下设备】 【云平台】按照 MQTT 协议规定的数据格式来通信(属于应用层);
3 基于【客户端 - 服务端】模式:云下设备 = 客户端,云端设备 = 服务端;
4 基于 消息发布[ PUBLISH ] / 消息订阅 [ SUBSCRIBE ] 模式;
【请求 / 回答】模式:双方打电话(必须等到接电话才能交流),同步模式;
【发布 / 订阅】模式:发邮件(邮件发送完就不用管,收件人可以任何时间查看邮件),间接联系;
MQTT通信的示意图:
可以看到,每个客户端只和MQTT服务端连接。当客户端向服务器发布带有主题的消息时,MQTT服务器会将消息分发给订阅主题的客户端。
MQTT的客户端和服务端:
作为客户端,可以发布、订阅、取消订阅消息,以及断开连接(通常根据心跳包会一直连接)。
作为服务器,要接收数据,处理订阅 / 取消订阅,分发消息等功能。
订阅、主题和会话:
数据表示(使用标准ASCII:0 ~ 127):
数据帧格式(前两个字节表示字符串长度):
MQTT控制报文
MQTT控制报文的结构:
MQTT控制报文有14种类型:
其中这3种只有在 Qos = 2才需要使用,百度云、阿里云、腾讯云都只支持【Qos = 0 ,Qos = 1】,不支持Qos = 2。
前面看到,MQTT由3部分构成:固定报头、可变报头和有效载荷。
固定报头:
固定报头的 字节1 包括两部分:MQTT控制报文的类型和标志位。其中,报文类型就是上面的14种,标志位如下所示:
可以看到,除发布消息的控制报文外,其他的标志位都是固定的;
剩余字节(变长编码,类似于GB2312兼容ASCII的原理):
剩余长度的大小表示:
可变报头:
某些控制报文中,包含一个可变报头部分,它在固定报头和负载之间,可变报头的报文标识符(Packet Identifier)字段存在于多个类型的报文里。
以下是包含报文标识符的控制报文:
客户端和服务器的报文标识符相互独立:
有效载荷:
某些MQTT控制报文在报文的最后部分包含一个有效载荷,对于PUBLISH来说有效载荷就是应用消息。
MQTT服务质量等级
服务质量等级 QoS:
QoS = 0:最多分发一次
使用场景:尽力而为,常用于广播。
QoS = 1:至少分发一次
使用场景:保证送达,可能重复(因为有可能Client网络不好,没收到PUBACK报文,从而重复发布报文给服务器)。
交互方式:
Client[Qos=1,DUP=0/*重复次数*/,MessageId=x]--->PUBLISH--> Server收到后,存储Message,发布,删除,向Client回发PUBACK。
Client收到PUBACK后,删除Message;如果未收到PUBACK,设置DUP++,重新发送,Server端重新发布,所以有可能重复发送消息。
QoS = 2:仅分发一次
这是最高等级的服务质量,消息丢失和重复都是不可接受的。使用这个服务质量等级会有额外的开销。QoS = 2使用PUBREC、PUBREL、PUBCOMP,即发布收到、发布释放、发布完成来实现。
注意:百度云、阿里云、腾讯云都不支持QoS = 2。
注意:QoS有 发布消息的Qos 和 订阅主题的Qos ,二者是独立的。发布消息的Qos是客户端向服务器发布消息时的服务质量等级,是否需要应答;订阅主题的Qos表示MQTT服务器向客户端分发时,是否需要应答。
MQTT控制报文
1 CONNECT 连接服务端
CONNECT报文的固定报头:
可变报头的组成:
1 协议名(Protocol Name)6 字节:
2 协议级别(Protocol Level):
3 连接标志:
连接标志字节包含一些用于指定MQTT连接行为的参数。它还指出有效载荷中的字段是否存在。
连接标志的位0:必须始终为0,否则断开连接;
连接标志的位1:清理会话;
会话的状态包括以下:
基于以下要求,我们一般设置为0;
连接标志的位2:遗嘱标志;
如果一个设备创建了遗嘱消息,当从MQTT服务端异常断开时,MQTT服务端会将这个设备的遗嘱消息分发给所有订阅了遗嘱主题的其他设备。
连接标志的位3 4:遗嘱消息服务质量等级;
连接标志的位5:遗嘱保留;
连接标志的位7:用户名标志;
连接标志的位6:密码标志;
保持连接(防止TCP连接断开):2 字节
有效载荷:
每一个UTF-8字符串编码,都包含2字节的长度数据,和0 ~ 65535的有效数据。
有效载荷:
2 CONNACK - 确认连接请求
服务端发送CONNACK报文响应从客户端收到的CONNECT报文。服务端发送给客户端的第一个报文必须是CONNACK。
可变报头部分数据格式:
连接确认标志位:
连接返回码(可变报头的第 2 个字节):
如果服务端收到一个合法的CONNECT报文,但出于某些原因无法处理它,服务端应该尝试发送一个包含非零返回码的CONNACK报文。如果服务端发送了一个包含非零返回码的CONNACK报文,那么它必须关闭网络连接。
CONNACK报文没有有效载荷。
3 PUBLISH - 发布消息
1 DUP 重发标志
2 保留标志
如果保留标志为1,服务器会保留这条消息。如果将来有新的订阅者,服务器会将这条消息分发给新的订阅者。比如,在微信公众号上写文章,这些文章都被微信的服务器保留下来,当我们去关注了这个公众号时,就能查看到之前所有的文章。
可变报头:
示例:
对应的字符串:
有效载荷:
动作:
4 PUBACK - 发布确认
8 SUBSRIBE - 订阅主题
1 固定报头:
2 可变报头:
可变报头包括报文标识符。如报文标识符 = 10的示例:
3 有效载荷
示例如下,两个主题是“a / b” 和 “c / d”。
则有效载荷字符串应该为:
9 SUBACK - 订阅确认
1 固定报头
2 可变报头:
包含2字节报文标识符。
3 有效载荷:
10 UNSUBSRIBE - 取消订阅
1 固定报头:
2 可变报头,包含包头标识符;
3 有效载荷
取消订阅示例:包含两个主题 “a / b” 和 “c / d”。
11 UNSUBACK - 取消订阅确认
服务端发送UNSUBACK报文给客户端用于确认收到UNSUBSCRIBE报文。
1 固定报头;
2 可变报头,2 字节报文标识符;
12 PINGREQ - 心跳请求
1 固定报头:
无可变报头,无有效载荷。
13 PINGRESP - 心跳响应
14 DISCONNECT - 断开连接
操作行为
1 网络连接
2 通配符:
所谓的层级结构,类似于多层文件夹,通过通配符,可以获得某个文件夹下的所有内容(订阅这个主题下的所有主题)。
主题语义的规格和用法:
来源:CSDN
作者:小小刘木子
链接:https://blog.csdn.net/dingyc_ee/article/details/103480837