微信小程序使用MQTT远程控制单片机——MQTT控制报文②

MQTT控制报文——MQTT控制报文①

客户端到服务端的网络连接建立后,客户端发送给服务端的第一个报文必须是CONNECT报文
在一个网络连接上,客户端只能发送一次CONNECT报文。服务端必须将客户端发送的第二个CONNECT报文当作协议违规处理并断开客户端的连接。
有效载荷包含一个或多个编码的字段。包括客户端的唯一标识符,Will主题,Will消息,用户名和密码。除了客户端标识之外,其它的字段都是可选的,基于标志位来决定可变报头中是否需要包含这些字段。

A:固定报头 Fixed header

这里的报文类型以及保留位的都是确定的,但是剩余长度还需要后面的长度确定所以这里为止用xx表示也就是说是:10 xx,注意这里的数全部都是十六进制
报文表示为:10 xx
在这里插入图片描述
剩余长度字段

  • 剩余长度等于可变报头的长度(10字节)加上有效载荷的长度。编码方式见 2.2.3节的说明。

B:可变报头 Variable header

CONNECT报文的可变报头按下列次序包含四个字段:协议名(Protocol Name),协议级别(Protocol Level),连接标志(Connect Flags)和保持连接(Keep Alive)。
总报文表示为:00 04 4D 51 54 54 04 c2 00 64

协议名(Protocol Name)

这里的协议名字段前两个字节可表示为00 04,后四个字节为'M' 'Q' 'T ' ' T'转换为十六进制4D 51 54 54,所以这六个字节表示为:00 04 4D 51 54 54
在这里插入图片描述

  • 协议名是表示协议名 MQTT 的UTF-8编码的字符串。MQTT规范的后续版本不会改变这个字符串的偏移和长度。

  • 如果协议名不正确服务端可以断开客户端的连接,也可以按照某些其它规范继续处理CONNECT报文。对于后一种情况,按照本规范,服务端不能继续处理CONNECT报文 [MQTT-3.1.2-1]。

协议级别(Protocol Level)

该字节表示为:04
客户端用8位的无符号值表示协议的修订版本。对于3.1.1版协议,协议级别字段的值是4(0x04)。如果发现不支持的协议级别,服务端必须给发送一个返回码为0x01(不支持的协议级别)的CONNACK报文响应CONNECT报文,然后断开客户端的连接在这里插入图片描述

连接标志(Connect Flags)

连接标志字节包含一些用于指定MQTT连接行为的参数。它还指出有效载荷中的字段是否存在。
在这里插入图片描述

  • 服务端必须验证CONNECT控制报文的保留标志位(第0位)是否为0,如果不为0必须断开客户端连接
a. 清理会话 Clean Session

位置:连接标志字节的第1位

  • 这个二进制位指定了会话状态的处理方式。 客户端和服务端可以保存会话状态,以支持跨网络连接的可靠消息传输。这个标志位用于控制会话状态的生存时间。

  • 如果清理会话(CleanSession)标志被设置为0,服务端必须基于当前会话(使用客户端标识符识别)的状态恢复与客户端的通信。如果没有与这个客户端标识符关联的会话,服务端必须创建一个新的会话。在连接断开之后,当连接断开后,客户端和服务端必须保存会话信息 。当清理会话标志为0的会话连接断开之后,服务端必须将之后的QoS 1和QoS 2级别的消息保存为会话状态的一部分,如果这些消息匹配断开连接时客户端的任何订阅。服务端也可以保存满足相同条件的QoS 0级别的消息。

  • 如果清理会话(CleanSession)标志被设置为1,客户端和服务端必须丢弃之前的任何会话并开始一个新的会话。会话仅持续和网络连接同样长的时间。与这个会话关联的状态数据不能被任何之后的会话重用 。

客户端的会话状态包括

  • 已经发送给服务端,但是还没有完成确认的QoS 1和QoS 2级别的消息
  • 已从服务端接收,但是还没有完成确认的QoS 2级别的消息。
  • 服务端的会话状态包括:
  • 会话是否存在,即使会话状态的其它部分都是空。

客户端的订阅信息。

  • 已经发送给客户端,但是还没有完成确认的QoS 1和QoS 2级别的消息。
  • 即将传输给客户端的QoS 1和QoS 2级别的消息。
  • 已从客户端接收,但是还没有完成确认的QoS 2级别的消息。
  • 可选,准备发送给客户端的QoS 0级别的消息。
  • 保留消息不是服务端会话状态的一部分,会话终止时不能删除保留消息 [MQTT-3.1.2.7]。
  • 有关状态存储的限制和细节见第 4.1节。
    当清理会话标志被设置为1时,客户端和服务端的状态删除不需要是原子操作。
b. 遗嘱标志 Will Flag

位置:连接标志的第2位。

  • 遗嘱标志(Will Flag)被设置为1,表示如果连接请求被接受了,遗嘱(Will Message)消息必须被存储在服务端并且与这个网络连接关联。之后网络连接关闭时,服务端必须发布这个遗嘱消息,除非服务端收到DISCONNECT报文时删除了这个遗嘱消息 。

  • 遗嘱消息发布的条件,包括但不限于:

    • 服务端检测到了一个I/O错误或者网络故障。
      客户端在保持连接(Keep Alive)的时间内未能通讯。
      客户端没有先发送DISCONNECT报文直接关闭了网络连接。
      由于协议错误服务端关闭了网络连接。
      如果遗嘱标志被设置为1,连接标志中的Will QoS和Will Retain字段会被服务端用到,同时有效载荷中必须包含Will Topic和Will Message字段 。
  • 一旦被发布或者服务端收到了客户端发送的DISCONNECT报文,遗嘱消息就必须从存储的会话状态中移除。

  • 如果遗嘱标志被设置为0,连接标志中的Will QoS和Will Retain字段必须设置为0,并且有效载荷中不能包含Will Topic和Will Message字段 。

  • 如果遗嘱标志被设置为0,网络连接断开时,不能发送遗嘱消息 。

  • 服务端应该迅速发布遗嘱消息。在关机或故障的情况下,服务端可以推迟遗嘱消息的发布直到之后的重启。如果发生了这种情况,在服务器故障和遗嘱消息被发布之间可能会有一个延迟。

c. 遗嘱QoS Will QoS

位置:连接标志的第4和第3位。

  • 这两位用于指定发布遗嘱消息时使用的服务质量等级。

  • 如果遗嘱标志被设置为0,遗嘱QoS也必须设置为0(0x00)

  • 如果遗嘱标志被设置为1,遗嘱QoS的值可以等于0(0x00),1(0x01),2(0x02)。它的值不能等于3 。

d. 遗嘱保留 Will Retain

位置:连接标志的第5位。

  • 如果遗嘱消息被发布时需要保留,需要指定这一位的值。

  • 如果遗嘱标志被设置为0,遗嘱保留(Will Retain)标志也必须设置为0 。

  • 如果遗嘱标志被设置为1:

  • 如果遗嘱保留被设置为0,服务端必须将遗嘱消息当作非保留消息发布 。

  • 如果遗嘱保留被设置为1,服务端必须将遗嘱消息当作保留消息发布 。

e. 用户名标志 User Name Flag

位置:连接标志的第7位。

  • 如果用户名(User Name)标志被设置为0,有效载荷中不能包含用户名字段 。
  • 如果用户名(User Name)标志被设置为1,有效载荷中必须包含用户名字段。
f. 密码标志 Password Flag

位置:连接标志的第6位。

  • 如果密码(Password)标志被设置为0,有效载荷中不能包含密码字段 。
  • 如果密码(Password)标志被设置为1,有效载荷中必须包含密码字段 。
  • 如果用户名标志被设置为0,密码标志也必须设置为0
连接选择

遗嘱标志字节以及保留字节暂时不设置。所以我们只设置几个标志位

这里的连接标志字段要根据阿里云的MQTT协议来进行确定字节报文,所以该字段字节表示为:c2(1100010)

在这里插入图片描述
在这里插入图片描述

保持连接(Keep Alive)

这里我们设置保持连接时间间隔为100s,该字段字节表示为:00 64
在这里插入图片描述

  • 保持连接(Keep Alive)是一个以秒为单位的时间间隔,表示为一个16位的字,它是指在客户端传输完成一个控制报文的时刻到发送下一个报文的时刻,两者之间允许空闲的最大时间间隔。客户端负责保证控制报文发送的时间间隔不超过保持连接的值。如果没有任何其它的控制报文可以发送,客户端必须发送一个PINGREQ报文。

  • 不管保持连接的值是多少,客户端任何时候都可以发送PINGREQ报文,并且使用PINGRESP报文判断网络和服务端的活动状态。

  • 如果保持连接的值非零,并且服务端在一点五倍的保持连接时间内没有收到客户端的控制报文,它必须断开客户端的网络连接,认为网络连接已断开。

  • 客户端发送了PINGREQ报文之后,如果在合理的时间内仍没有收到PINGRESP报文,它应该关闭到服务端的网络连接。

  • 保持连接的值为零表示关闭保持连接功能。这意味着,服务端不需要因为客户端不活跃而断开连接。注意:不管保持连接的值是多少,任何时候,只要服务端认为客户端是不活跃或无响应的,可以断开客户端的连接。

可变报头非规范示例

可变报头一共有10个字节,byte 8 byte9 byte10,分别为连接标志保持连接,可以随便设置,其他是固定
在这里插入图片描述

C:有效载荷 Payload

CONNECT报文的有效载荷(payload)包含一个或多个以长度为前缀的字段,可变报头中的标志决定是否包含这些字段。如果包含的话,必须按这个顺序出现:客户端标识符,遗嘱主题,遗嘱消息,用户名,密码 [MQTT-3.1.3-1]。
总报文字节为:00 26 5A 30 30 31 7C 73 65 63 75 72 65 6D 6F 64 65 3D 33 2C 73 69 67 6E 6D 65 74 68 6F 64 3D 68 6D 61 63 73 68 61 31 7C 00 10 5A 30 30 31 26 61 31 58 73 68 74 73 6B 74 4A 56 00 2864 38 38 36 36 37 34 65 64 39 39 34 35 30 39 33 65 33 32 35 63 66 63 34 65 36 39 30 32 37 38 33 63 37 65 36 35 63 35 35

1. 客户端标识符 Client Identifier

  • 服务端使用客户端标识符 (ClientId) 识别客户端。连接服务端的每个客户端都有唯一的客户端标识符(ClientId)。客户端和服务端都必须使用ClientId识别两者之间的MQTT会话相关的状态。

  • 客户端标识符 (ClientId) 必须存在而且必须是CONNECT报文有效载荷的第一个字段。

  • 客户端标识符必须是1.5.3节定义的UTF-8编码字符串 。

  • 服务端必须允许1到23个字节长的UTF-8编码的客户端标识符,客户端标识符只能包含这些字符:“0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ”(大写字母,小写字母和数字)。

  • 服务端可以允许编码后超过23个字节的客户端标识符 (ClientId)。服务端可以允许包含不是上面列表字符的客户端标识符 (ClientId)。

  • 服务端可以允许客户端提供一个零字节的客户端标识符 (ClientId) ,如果这样做了,服务端必须将这看作特殊情况并分配唯一的客户端标识符给那个客户端。然后它必须假设客户端提供了那个唯一的客户端标识符,正常处理这个CONNECT报文。

  • 如果客户端提供了一个零字节的客户端标识符,它必须同时将清理会话标志设置为1。

  • 如果客户端提供的ClientId为零字节且清理会话标志为0,服务端必须发送返回码为0x02(表示标识符不合格)的CONNACK报文响应客户端的CONNECT报文,然后关闭网络连接。

  • 如果服务端拒绝了这个ClientId,它必须发送返回码为0x02(表示标识符不合格)的CONNACK报文响应客户端的CONNECT报文,然后关闭网络连接。

2. 遗嘱主题 Will Topic

  • 如果遗嘱标志被设置为1,有效载荷的下一个字段是遗嘱主题(Will Topic)。

3. 遗嘱消息 Will Message

  • 如果遗嘱标志被设置为1,有效载荷的下一个字段是遗嘱消息。遗嘱消息定义了将被发布到遗嘱主题的应用消息。这个字段由一个两字节的长度和遗嘱消息的有效载荷组成,表示为零字节或多个字节序列。长度给出了跟在后面的数据的字节数,不包含长度字段本身占用的两个字节。

  • 遗嘱消息被发布到遗嘱主题时,它的有效载荷只包含这个字段的数据部分,不包含开头的两个长度字节。

4. 用户名 User Name

  • 如果用户名(User Name)标志被设置为1,有效载荷的下一个字段就是它。用户名必须是 1.5.3节定义的UTF-8编码字符串。服务端可以将它用于身份验证和授权。

5. 密码 Password

  • 如果密码(Password)标志被设置为1,有效载荷的下一个字段就是它。密码字段包含一个两字节的长度字段,长度表示二进制数据的字节数(不包含长度字段本身占用的两个字节),后面跟着0到65535字节的二进制数据。

6. 客户端连接报文

我们可以根据上面设置的可变报头里的连接标志选择有效负载的连接标志字段,所以这里就只是选择了客户端标识符、用户名、密码。

在这里插入图片描述

模型:

客户端标识符*|securemode=3,signmethod=hmacsha1| ( * )DeviceName 注意替换
用户名*&# ( * )DeviceName ( # )ProductKey 注意替换
密码 : 用DeviceSecret做为秘钥对clientId*deviceName*productKey#进行hmacsha1加密后的结果 (*)设备名称 (#)ProductKey 注意替换。

常用加密网址:http://encode.chahuo.com/选择hmacsha1加密方式

在这里插入图片描述
在这里插入图片描述
替换后为

客户端标识符Z001|securemode=3,signmethod=hmacsha1|
用户名Z001&a1XshtsktJV
密码clientIdZ001deviceNameZ001productKeya1XshtsktJV加密后为:d886674ed9945093e325cfc4e6902783c7e65c55

换算为十六进制为

客户端标识符 :5A 30 30 31 7C 73 65 63 75 72 65 6D 6F 64 65 3D 33 2C 73 69 67 6E 6D 65 74 68 6F 64 3D 68 6D 61 63 73 68 61 31 7C—— 00 26
用户名 : 5A 30 30 31 26 61 31 58 73 68 74 73 6B 74 4A 56——00 10
密码 :64 38 38 36 36 37 34 65 64 39 39 34 35 30 39 33 65 33 32 35 63 66 63 34 65 36 39 30 32 37 38 33 63 37 65 36 35 63 35 35—— 00 28
注意:末尾的空格不能要

所以 有效载荷字段字节为:5A 30 30 31 7C 73 65 63 75 72 65 6D 6F 64 65 3D 33 2C 73 69 67 6E 6D 65 74 68 6F 64 3D 68 6D 61 63 73 68 61 31 7C 5A 30 30 31 26 61 31 58 73 68 74 73 6B 74 4A 56 64 38 38 36 36 37 34 65 64 39 39 34 35 30 39 33 65 33 32 35 63 66 63 34 65 36 39 30 32 37 38 33 63 37 65 36 35 63 35 35。但是这样写壳不行,这样我们就分不清客户端标识符,用户名,密码是什么,把这三个挨到一块,没个标点符号啥的,不好区分,所以我们把客户端标识符,用户名,密码的数据长度分别作为区分三者,即把这三者数据长度换算为两个字节的十六进制。所以为:00 26 5A 30 30 31 7C 73 65 63 75 72 65 6D 6F 64 65 3D 33 2C 73 69 67 6E 6D 65 74 68 6F 64 3D 68 6D 61 63 73 68 61 31 7C 00 10 5A 30 30 31 26 61 31 58 73 68 74 73 6B 74 4A 56 00 28 64 38 38 36 36 37 34 65 64 39 39 34 35 30 39 33 65 33 32 35 63 66 63 34 65 36 39 30 32 37 38 33 63 37 65 36 35 63 35 35

CONNECT(连接服务器)的总报文

汇总起来的报文为:10 xx 00 04 4D 51 54 54 04 c2 00 64 00 26 5A 30 30 31 7C 73 65 63 75 72 65 6D 6F 64 65 3D 33 2C 73 69 67 6E 6D 65 74 68 6F 64 3D 68 6D 61 63 73 68 61 31 7C 00 10 5A 30 30 31 26 61 31 58 73 68 74 73 6B 74 4A 56 00 2864 38 38 36 36 37 34 65 64 39 39 34 35 30 39 33 65 33 32 35 63 66 63 34 65 36 39 30 32 37 38 33 63 37 65 36 35 63 35 35
注意这里xx是剩余长度,也就是xx后面的总长度,计算可得十六进制总字节数为6E,所以:10 6E 00 04 4D 51 54 54 04 c2 00 64 00 26 5A 30 30 31 7C 73 65 63 75 72 65 6D 6F 64 65 3D 33 2C 73 69 67 6E 6D 65 74 68 6F 64 3D 68 6D 61 63 73 68 61 31 7C 00 10 5A 30 30 31 26 61 31 58 73 68 74 73 6B 74 4A 56 00 2864 38 38 36 36 37 34 65 64 39 39 34 35 30 39 33 65 33 32 35 63 66 63 34 65 36 39 30 32 37 38 33 63 37 65 36 35 63 35 35

测试

我们用串口测试是否连接成功
我们根据阿里云MQTT协议文档可知,我们的域名,也就远程主机的地址就是这个:${YourProductKey}.iot-as-mqtt.${YourRegionId}.aliyuncs.com:1883,代入我们阿里云上的设备:a1XshtsktJV.iot-as-mqtt.cn-shanghai.aliyuncs.com:1883
在这里插入图片描述
这里选择的串口调试助手:链接:https://pan.baidu.com/s/130pMR99SxFupwH_iPmgw7w提取码:8c09
在这里插入图片描述
我可以看出,我们连接成功,而且返回了一些数据,这些数据是什么?我们可以看MQTT中文档解释:

这里第一个字节为二进制:00100000,也就是十六进制的0x20第二个字节是剩余长度固定为2,也就是十六进制的02
在这里插入图片描述

这里的可变报头的第一个字节必须为0,也就是说第三个字节00
在这里插入图片描述

这里最后一个字节为返回码也为0
在这里插入图片描述
所以总为:20 03 00 00 符合返回的值

持续更新

微信小程序使用MQTT远程控制单片机——阿里云物联网平台①

微信小程序使用MQTT远程控制单片机——MQTT控制报文②

微信小程序使用MQTT远程控制单片机——MQTT控制报文③
学习视频
该博文为个人学习笔记记录,由于知识量储备不够若有错误之处或者补充,请各位大佬批评指正,持续更新中……

  • 5
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值