文章插图
由此我们可以确定整个报文的第一字节为0x10(为了书写方便后续将不在写0x这个十六进制的标号,将直接使用10标识) 。
2)第二字节(也有可能是第2到第3、或者2到4,或者2到5)为什么会有不同的选择 , 这是由于在第一字节确定了本包报文是什么类型后 , 会在后续告诉对方后面的可变报头和负载一共有多少字节,当后面只有120个字节时可以用一个字节就表示好,但是当有500,或者1000时就不是一个字节可以表示的长度了(二进制表示方式,不理解的这里可以自己百度) 。为什么会有500,或者1000的那么大的差别呢 , 这由于有些可选配置,如有需要可配置进去(然后再后面的可变报头给对应的bit位写1 , 表示我要使用改配置,那么服务端检测到该标志就可以知道说原来你本次有这个可选配置 , 我会在检测负载数据时进行检测读取的),然后就是如果你设置设备名字或者密码等时给了一个很长的名字,那数据不就是增加了,所以才在这把长度搞成这样的可?。缓蠡咕厥獾纳柚萌媒邮丈璞缚梢院芎玫闹辣敬伪ㄎ恼獠糠值降褪怯眉父鲎纸诒硎竞竺媸莸某ざ?,接下来我们会详细讲解一下,先把截图放在下面 , 这就是为什么剩余长度bute2...有三个点的原因:
文章插图
文章插图
分别表示(每个字节的低 7 位用于编码数据 , 最高位是标志位) :1 个字节时(整个报文包的第2字节), 从 0(0x00)到 127(0x7f)2 个字节时(整个报文包的第2字节和第3字节) , 从 128(0x80,0x01)到 16383(0Xff,0x7f)3 个字节时(整个报文包的第2、3、4字节),从 16384(0x80,0x80,0x01)到 2097151(0xFF,0xFF,0x7F)4 个字节时(整个报文包的第2、3、4、5字节) , 从 2097152(0x80,0x80,0x80,0x01)到 268435455(0xFF,0xFF,0xFF,0x7F))
长度计算方式:
每个字节只取前面7位表示数据,第8位表示有没有进位,如果第8位为1就表示有进位,长度还应该检查第3字节的前前7位来乘128,因为2的7次方为128(这里不明白为什么是2的7次方可以百度),同理第3字节的第八为如果也是1,那么就应该检查第4字节来加入计算,注意这里是乘于128*128,一直到第5字节:
eg1:假设我们现在有的可变报头和负载一共有100(十进制)字节数据
100(十进制)的十六进制为0x64——所以我们该部分只有0x64即可
eg2:假设可变报头和负载一共有500个数据(十进制)字节数据
500/128=3剩余116,那么116转化为0x74,但是由于有进位所以第8位应该为1 , 所以原本的0x74(01110100)第8位变1(11110100)0xF4,所以第二字节为0xF4,那么由于有进位就有第三字节,所以第三字节为0x03 。
3)阿里云链接报文CONNECT的固定报头确定有上面的讲解,我们可以确定本次链接报文的固定报头为(十六进制):
10 ?(问号的意思是现在还不知道我们本次可变报头个负载数据长度,我们最后添加)
3.2.2、可变报头在MQTT协议栈中规定可变报头包含4个字段 , 分别为协议名(Protocol name)、协议级别(Protocol Level) , 连接标志(Protocol flags)、保持连接(Keep alive),下面我,来分别看一下 。
1)、协议名这一共6个字节,是协议直接规定的,我们直接带入就行,每一字节数据如下:
说明76543210byte1长度MSB(0)00000000byte2长度LSB(4)00000100byte3“M”01001101byte4“Q”01010001byte5“T”01010100byte6“T”01010100那根据协议规定我们可以得到如下的数据:
10 ?00 04 40 51 54 54
2)协议级别用一个字节表示协议级别 , 前面有说过我们使用和参考的协议为MQTT-V3.1.1 , 那么他的标识就是0x04,
文章插图
3)连接标志用一个字节表示链接标志,其中每一位都有不同的意思,连接标志如图标所示
文章插图
- clean session:0——不清除设备的连接信息,全新的设备A第一次连接记录了一下信息Aq , 那么第二次连接还是要有这些信息或者基于进行连接或者保留,1——每一次断开连接都清除连接记录
- Will Flag:0——没有遗嘱消息,1——有遗嘱消息(如当设备1,2,3都订阅了遗嘱消息,当1设备突然断电,导致还没有发DISCONNECT报文就断开了(还有其余情况下的错误),那么2和3这两个链接到服务器的设备就会收到一条1的遗嘱消息)
推荐阅读