mqtt_simple例程 nrf9160做主控连接阿里云——( 四 )


每个字节只取前面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,

mqtt_simple例程 nrf9160做主控连接阿里云——

文章插图
3)连接标志用一个字节表示链接标志,其中每一位都有不同的意思,连接标志如图标所示
mqtt_simple例程 nrf9160做主控连接阿里云——

文章插图
  • clean session:0——不清除设备的连接信息,全新的设备A第一次连接记录了一下信息Aq,那么第二次连接还是要有这些信息或者基于进行连接或者保留,1——每一次断开连接都清除连接记录
  • Will Flag:0——没有遗嘱消息,1——有遗嘱消息(如当设备1,2,3都订阅了遗嘱消息,当1设备突然断电,导致还没有发DISCONNECT报文就断开了(还有其余情况下的错误),那么2和3这两个链接到服务器的设备就会收到一条1的遗嘱消息)
  • Will QoS:用于指定发布遗嘱消息时使用的服务质量等级,0——(will flag=0时必须为零),当will flag=1时可以设置为0,1,2表示消息质量(如前面消息质量)
  • Will retain:遗嘱保留,0——不保留信息,掉线后从连无法获取信息,1——保留信息,掉线后重连可以获取信息(这一点我理解的是这样,不知道对不对,如有更好的解释可以在评论区讨论)
  • password flag:密码,0——在负载中不包含密码,1——在负载中包含密码
  • user name flag:用户名,0——在负载中不包含用户名,1——在负载中包含用户名
由于我们连接的是阿里云,阿里云要求必须是有用户名和密码的,不使用遗嘱消息,且有不保留信息,也就是要清除所以这一字节为(11000010)0xC2
4)保持连接这一部分为两个字节,在实际连接中,要不间断的在规定时间内给服务器发送PING保活包,那这个规定时间内时间是多长时间,就在这个设定好,当服务器和你连接完成后,如果你在这个时间内没有发送到PING包,那么服务器就认为你断开连接了 。单位是秒 。这里每个服务器在MQTT协议规定的最大时间内还可以规定自己的最大时间,本次测试就设定为100s(64s)内必须有PING包出现,不然就认为是断开连接,对于嵌入式设备来说这个时间越长越低功耗 。

经验总结扩展阅读