OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 5887|回复: 2

技术干货!网络调试助手直接连接阿里云?

[复制链接]

1155

主题

1167

帖子

2

精华

超级版主

Rank: 8Rank: 8

积分
4980
金钱
4980
注册时间
2019-5-8
在线时间
1259 小时
发表于 2021-7-6 16:21:38 | 显示全部楼层 |阅读模式
本帖最后由 正点原子运营 于 2021-11-1 10:45 编辑

以下文章摘自微信公众号——开源电子网《技术干货!网络调试助手直接连接阿里云?》
更多技术文章,请扫下方二维码关注

开源电子网,扫码2222222.png

浅谈MQTT底层原理
-网络调试助手直连阿里云



第一节 本文探讨的内容


  本文讨论MQTT协议底层数据收发的过程,直接通过网络调试助手与阿里云连接进行实验验证。本文不讲述阿里云的基础知识与创建阿里云设备,建议先初步学习MQTT协议API函数的使用和阿里云的简单操作再看本文。入门教程可参考正点原子推出的“STM32F1 lwIP开发手册.docx”的第12章。在本文第七节,我书写了一个网络调试助手直连阿里云的极速体验,想快速体验的小伙伴,可以先看一下第七节哇!

第二节 环境搭建

  本文讨论MQTT协议底层数据收发的过程,直接通过网络调试助手与阿里云连接进行实验验证。本文不讲述阿里云的基础知识与创建阿里云设备,建议先初步学习使用MQTT协议API函数使用和阿里云的简单操作再看本文。入门教程可参考正点原子推出的“STM32F1lwIP开发手册.docx”的第12章。
  准备阿里云已注册账号及设备,得到如图1.1所示的设备证书
1.png
图1.1 设备证书

  NetAssist网络调试助手 V5.0,下载地址如下,软件启动界面如图1.2所示。
  下载地址:
http://www.cmsoft.cn/resource/102.html


2.png
图1.2 网络调试助手启动界面

  我们现有以下信息(获取方式参考“STM32F1 lwIP开发手册.docx”的第12章):

● 服务器地址:
a1Dm4VEK8BR.iot-as-mqtt.cn-shanghai.aliyuncs.com
● 端口:1883
● 客户端ID:
aliyun_dev|securemode=3,signmethod=hmacsha1|
● 用户名:aliyun_dev&a1Dm4VEK8BR
● 计算登录密码:clientIdaliyun_devdeviceNamealiyun_devproductKeya1Dm4VEK8BR
● Password:
8bdc84f9963105d65bdc79b6cb3ac0cec9ce1aa9

(" Password"为hmacsha1加密后的密码,加密网站为:http://encode.chahuo.com
获取方式如图1.3所示。)

注意!由于你注册的阿里云和我的设备证书是不一样的,故得到的信息也不一样!

3.png
图1.3 网站上使用hmacsha1加密得到Password

  
第三节 MQTT控制报文格式

  为了进一步理解MQTT底层的原理,我们要先了解MTQQ控制报文的格式。

  MQTT控制报文由固定报头(Fixedheader)、可变报头 (Variableheader)、有效载荷(Payload)三部分组成。

  首先讲解MQTT固定报文,该报文是所有控制报文都包含的,固定报文至少2字节(byte1一定要有,剩余长度至少要一个字节表示),最多为5字节(因为剩余长度最多4字节),其格式如表2.1所示,MQTT控制报文类型如图2.2所示,控制报文标志如图2.3所示。根据下面的描述,我们可以得知不同类型报文的固定报头内容。


4.png
表2.1 固定报文格式

5.png
表2.2 MQTT控制报文类型

6.png
表2.3 MQTT控制报文标志

  报文的第二部分是可变报头,MQTT控制报文包含一个可变报头部分。它在固定报头和可变负载之间。可变报头的内容根据报文类型的不同而不同,此处我们在具体的报文中作讲解。

  报文的最后一个部分是可变负载,通俗来讲,这部分就是应用消息,因此也是具体的报文再作讲解。

  下面简介MQTT底层中需要了解的知识:

  1.UTF-8编码字符串

  MQTT的报文的格式是UTF-8编码的,因此需要了解该编码的格式才能进行MQTT通讯。
  UTF-8编码格式的要求为:每一个字符串都有一个两字节的长度字段作为前缀,它给出这个字符串UTF-8编码的字节数。因此,可以传送的UTF-8编码的字符串大小有一个限制,不能超过65535字节。
  例如字符串“123456”的UTF-8编码,可以将“123456”转换成ASCII码表示:3132 33 34 35 36(十六进制),字节数大小为:6,因此需要添加前缀0x00,0x06,综合原字符串ASCII码可得到该字符串最终的UTF-8编码为0006 31 32 33 34 35 36(十六进制)。

2.剩余长度

  剩余长度(RemainingLength)表示当前报文剩余部分的字节数,包括可变报头和负载的数据。剩余长度不包括用于编码剩余长度字段本身的字节数。
  剩余长度字段使用一个变长度编码方案,对小于128的值它使用单字节编码。更大的值按下面的方式处理。低7位有效位用于编码数据,最高有效位用于指示是否有更多的字节。因此每个字节可以编码128个数值和一个延续位( continuationbit )。剩余长度字段最大 4个字节。MQTT中剩余长度为低字节在前,高字节在后。例如(x为剩余长度,所有数都为十六进制)x 01 02 03 04 05 06,则剩余长度为后面的字节数,由于x<128,则x=06,再例如x01 200="" 02="" 03="">128,则x=01c8,但注意,在MQTT中剩余长度为低字节在前,高字节在后,x应该为c801。

3.服务质量QOS

  MQTT按照这里定义的服务质量(QoS)等级分发应用消息。QOS等级分为三个等级。
  QoS0: 最多分发一次,消息的分发依赖于底层网络的能力。接收者不会发送响应,发送者也不会重试。
  QoS1: 至少分发一次,服务质量确保消息至少送达一次。
  QoS2: 仅仅分发一次,这是最高等级的服务质量,消息丢失和重复都是不可接受的。使用这个服务质量等级会有额外的开销。
  本文是为了理解MQTT低层的工作原理,规定本文的所有QOS等级都为0。

  4. JSON 创建对象格式

  JSON对象使用在大括号中书写,对象可以包含多个key/value(键/值)对两个"键:值"对以逗号分隔,例如,定义名为people对象:
  1. "people":{
  2.   "ID":1001,
  3.   "name":"张三",
  4.   "age":24
  5.   }
  6.   或
  7.   varpeople={
  8.   "ID":1001,
  9.   "name":"张三",
  10.   "age":24
  11.   }
复制代码
  key必须是字符串,value可以是合法的JSON数据类型(字符串,数字,对象,数组,布尔值或者null);key和value中适用冒号(分割;每个键值对适用逗号(,)分割。
  JSON是一种纯数据格式,它只包含属性,没有方法。

  5.字符串与ASCII码之间的转换和获取字符长度的简易方法

  字符和ASCII的关系如图2.4所示,例如要知道字符’1’的ASCII码值可查找字元‘1’,然后对应行的左边的值就是ASCII码值,查找图2.4可知:字符‘1‘的ASCII码值为0x31或49(十进制)。字符串的ASCII码值是所有字符的ASCII码值组合,例如字符串“123456”的ASCII值为0x310x32 0x33 0x34 0x350x36。相反操作可以获取对应ASCII码值对应的字符,例如ASCII码值为0x31,表示的字符为‘1’。
  但是遇到字符串比较长的情况,查表找字符串的值较为繁琐。可通过网络调试助手进行转换,如图2.5所示,我们使用了127回播地址进行数值的返回,接收区设置为HEX(意为16进制显示),发送区选择ASCII发送,我们发送字符串后,将会返回对应的ASCII码值。如图2.6所示将发送区设置为HEX(意为16进制显示)发送,接收区设置为ASCII,便可将ASCII码值转换为字符串。值得注意的是网络调试助手的右下角还会显示发送(TX)与接收(RX)的字节数,右下角的复位计数可以重新计算发送、接收区的字符总数。

7.jpg
图2.4 字符和ASCII码值的关系

8.png
图2.5 利用网络调试助手获取字符串的ASCII码值

9.png
图2.5 利用网络调试助手获取ASCII码值对应的字符串


  
第四节 CONNEC报文

  客户端到服务端的网络连接建立后,客户端发送给服务端的第一个报文必须是CONNECT报文。服务端收到CONNECT报文后,将发送CONNACK报文响应从客户端收到的CONNECT报文。服务端发送给客户端的第一个报文也必须是CONNACK报文。下面讲解CONNECT报文的内容。
  CONNEC固定报头可由第三节得出,为0x10+(剩余长度)。
  CONNEC可变报头由协议名、协议级别、连接标志、保持连接四部分组成。协议名为字符串“MQTT”,由于规定为6字节,故其UTF-8编码格式的表示为:0004 4D 51 54 54(十六进制)。协议级别为4,即0x04。连接标志由1个字节组成,其含义表3.1所示,我们需要验证UserName、Password,并且CleanSession,这样服务器每次session都要重新建立,这也是大多数的场景使用情况,因此连接标志配置为0xC2。保持连接由两个字节组成,表示服务器和客户端保持连接的时间,此处设置为100s,也就是0x0064。综上所述,我们配置的CONNEC可变报文为0004 4D 51 54 54 04 C2 00 64(十六进制)。
  CONNEC报文的可变负载由三个字符串组成,分别为客户端ID、用户名、Password组成。此处注意字符串需要使用UTF-8格式的。


  综合上面CONNEC报文的三大部分,我们计算出剩余长度为0x7A,可以最终得到CONNEC报文发送的内容为:107A 00 04 4D 51 54 54 04 C2 00 64 00 2c 63 6F 61 70 5F 74 65 78 74 317C 73 65 63 75 72 65 6D 6F 64 65 3D 33 2C 73 69 67 6E 6D 65 74 68 6F64 3D 68 6D 61 63 73 68 61 31 7C 00 16 63 6F 61 70 5F 74 65 78 74 3126 61 31 31 36 6E 37 4D 77 53 78 67 00 28 61 32 38 31 62 38 38 38 6366 66 64 30 37 63 35 34 30 32 31 36 31 37 64 30 39 63 37 63 65 37 6135 34 37 33 65 39 38 64(十六进制,不同设备的CONNEC报文负载是不同的)。


  我们实验验证上诉理论的可行性,如图3.1所示,接收和发送设置都设置为HEX,将服务器地址和端口输入进去。然后在发送区发送CONNEC报文,此时阿里云端显示已经连接。并且服务区返回数据:2002 00 00(十六进制)。这串数据为CONNACK–确认连接请求报文,其固定报头为0x20、0x02,其中0x02表示剩余长度。后面两个数据0x00、0x00为可变报文,CONNACK报文无可变负载报文。第三个数据0x00为确定连接标志,这个在MQTT中固定为0x00,第四个数据含义如表3.3所示,我们接收到的第四个数据为0x00就表示连接已接受了。

10.png
表3.1 连接标志含义

11.png
图3.2 实验验证

12.png
表3.3 连接返回码的值


第五节 订阅和取消订阅

  首先讲解一下如何订阅主题,客户端向服务端发送SUBSCRIBE报文用于创建订阅,每个订阅注册客户端关心的主题。然后服务器将会返回一个SUBACK报文,用于确认它已收到并且正在处理SUBSCRIBE报文。
  SUBSCRIBE固定报头可由第三节得出,为0x82+(剩余长度)。
  SUBSCRIBE可变报头是客户端标识符,此处我们使用的标识符号为0x000x0a。
  SUBSCRIBE报文的可变负载由主题过滤器(UTF-8字符串)和服务质量等级组成,我们的服务质量等级为0。主题过滤器其实就是Toic列表中的主题,我选取我阿里云上的主题“/a1Dm4VEK8BR/aliyun_dev/user/LED”。综合可得SUBSCRIBE报文的可变负载的可变负载内容为0020 2F 61 31 44 6D 34 56 45 4B 38 42 52 2F 61 6C 69 79 75 6E 5F 64 6576 2F 75 73 65 72 2F 4C 45 44 00(十六进制)


  综上,我们的SUBSCRIBE报文的内容为8225 00 0a 00 20 2F 61 31 44 6D 34 56 45 4B 38 42 52 2F 61 6C 69 79 756E 5F 64 65 76 2F 75 73 65 72 2F 4C 45 4400(十六进制)。如图4.1,我们连接阿里云服务器后,再发送SUBSCRIBE报文的内容。
  发送上面的消息后,我们将会收到订阅确认报文—SUBACK报文。该报文的固定报文为0x90+可变长度(大小一般固定为03)。可变报文为客户端发送的标识符。有效负载为一个字节,内容和含义为:0x00- 最大QoS0;0x01- 成功– 最大 QoS1;0x02- 成功– 最大 QoS2;0x80- Failure 失败。如图4.1,我们的返回值为9003 00 0A01,订阅成功!这里值得注意的是,我们虽然设置了QoS为0,但是SUBACK报文的有效负载为01,这并不是服务器出问题,而是我们成功后,等级应该会默认设置为最大QoS1。


  以上是订阅主题的操作,那么如果我们要取消订阅,就要使用UNSUBSCRIBE报文,其格式和SUBSCRIBE报文类似,当我们发送了UNSUBSCRIBE报文后,服务器也会返回UNSUBACK报文给客户端用于确认收到UNSUBSCRIBE报文。
  下面讲解一下UNSUBSCRIBE报文,该报文的固定报头由第三节得出,为0xa2+(剩余长度)。可变报头为SUBSCRIBE可变报头的客户端标识符,我的UNSUBSCRIBE可变报头为0x000x0a。UNSUBSCRIBE报文的有效载荷由要取消订阅的主题和QOS等级组成,当QOS等级=0时,可以省略QOS等级,我们要取消订阅的主题为
“/a1Dm4VEK8BR/aliyun_dev/user/LED”。


  综合本段的内容,我们可以得出完整的UNSUBSCRIBE报文为:a224 00 0a 00 20 2F 61 31 44 6D 34 56 45 4B 38 42 52 2F 61 6C 69 79 756E 5F 64 65 76 2F 75 73 65 72 2F 4C 45 44(十六进制)
  我们连接阿里云服务器,发送上述的UNSUBSCRIBE报文,如图4.1,服务端返回了UNSUBACK报文给客户端用于确认收到UNSUBSCRIBE报文,从图中可见到返回值为0xB0,0x02,0x00,0x0a。如果掌握了前述报文的内容,这个报文并不难分析。数据0xB0,0x02为固定报头,数据0x00,0x0a为可变报头,内容与SUBSCRIBE可变报头的客户端标识符一样,UNSUBACK报文无有效负载部分。如图4.1所示,我们成功取消了订阅。

13.png
图4.1 订阅和取消订阅


第六节 接收消息和发布消息

  经过前面几节的学习,我们已经初步了解MQTT底层的工作原理。本节先讲解设备如何接收阿里云的消息再讲解如何发布消息。我们在网络调试助手连接阿里云如图5.1所示,然后按照图示的六个步骤发送消息给网络助手。我们在网络调试助手的返回信息分析,可知固定报头为30,剩余长度为0x9b,此处不做累述,固定报头的格式可参考第一节。可变报头中,将0036 2F 73 79 73 2F 61 31 44 6D 34 56 45 4B 38 42 52 2F 61 6C 69 79 756E 5F 64 65 76 2F 74 68 69 6E 67 2F 73 65 72 76 69 63 65 2F 70 72 6F70 65 72 74 79 2F 73 6574(十六进制,UTF-8编码)翻译后的意思为“/sys/a1Dm4VEK8BR/aliyun_dev/thing/service/property/set”,可以判断可变报头的内容为Topic名称。
  剩下的数据即为有效载荷:7B22 6D 65 74 68 6F 64 22 3A 22 74 68 69 6E 67 2E 73 65 72 76 69 63 652E 70 72 6F 70 65 72 74 79 2E 73 65 74 22 2C 22 69 64 22 3A 22 37 3531 34 31 33 35 37 30 22 2C 22 70 61 72 61 6D 73 22 3A 7B 22 4C 45 4453 77 69 74 63 68 22 3A 30 7D 2C 22 76 65 72 73 69 6F 6E 22 3A 22 312E 30 2E 30 22 7D(十六进制,ASCII编码)。翻译后的意思如下:
“{"method":"thing.service.property.set","id":"751413570","params":{"LEDSwitch":0},"version":"1.0.0"}”这个明显为JSON表达式,JSON格式参考第三节“MQTT底层中需要了解的知识”。
 综上所述,我们可以MQTT中发布消息的格式为:
  ①固定报头:0x30+剩余长度
  ②可变报头:Topic名称(UTF-8编码)
  ③报文负载:应用消息(JSON格式,ASCII编码)


  下面我们按照上面的格式也尝试发消息给阿里云,我们先创建好了阿里云的设备LEDSwitch,并且打开自定义功能并发布上线(此处可参考正点原子推出的“STM32F1lwIP开发手册.docx”的第十二章),我们发布消息给物理模型,需要订阅主题“/sys/(ProductKey)/(DeviceName)/thing/event/property/set”(”ProductKey”和“DeviceName”根据自己设备填写,我最终订阅的主题内容为“/sys/a1Dm4VEK8BR/aliyun_dev/thing/event/property/set”,订阅方法参考本文第五节)。然后在发送消息中,我们写入如下内容:
①固定报头0x30+剩余长度
②可变报头:
“/sys/a1Dm4VEK8BR/aliyun_dev/thing/event/property/post”(UTF-8编码)
③报文负载:
{"method":"thing.event.property.post","id":"00000001","params":{"LEDSwitch":0},"version":"1.0.0"}。注意此处method中的内容不同于阿里云服务器发送消息的method内容,ID我们填写00000001,内容是使LED的状态为0(也可以设置为1),版本号填写“1.0.0”便可。
  综上3点我们最终的报文为:3098 01 00 35 2F 73 79 73 2F 61 31 44 6D 34 56 45 4B 38 42 52 2F 61 6C69 79 75 6E 5F 64 65 76 2F 74 68 69 6E 67 2F 65 76 65 6E 74 2F 70 726F 70 65 72 74 79 2F 70 6F 73 74 7B 22 6D 65 74 68 6F 64 22 3A 22 7468 69 6E 67 2E 65 76 65 6E 74 2E 70 72 6F 70 65 72 74 79 2E 70 6F 7374 22 2C 22 69 64 22 3A 22 30 30 30 30 30 30 30 31 22 2C 22 70 61 7261 6D 73 22 3A 7B 22 4C 45 44 53 77 69 74 63 68 22 3A 30 7D 2C 22 7665 72 73 69 6F 6E 22 3A 22 31 2E 30 2E 30 22 7D
  连接阿里云后,我们发送上述最终报文,结果如图5.2所示,我们成功使LEDSwitch的状态变为0。

14.png
图5.1 网络调试助手接收阿里云的消息

15.png
图5.2 网络调试助手向阿里云发送消息



第七节 网络调试助手直连阿里云极速体验

  第一步,如图6.1打开网络调试助手 V5.0下载地址:
   http://www.cmsoft.cn/resource/102.html
  选择协议类型为“TCP Client”,接收区设置为HEX,发送区设置为HEX。将远程主机地址填写为“a1Dm4VEK8BR.iot-as-mqtt.cn-shanghai.aliyuncs.com”,端口填写“1883”。在点击连接前先将数据“10 7A 00 04 4D 51 54 54 04 C2 00 64 00 2c 61 6C 69 79 75 6E 5F 64 65 76 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 16 61 6C 69 79 75 6E 5F 64 65 76 26 61 31 44 6D 34 56 45 4B 38 42 52 00 28 38 62 64 63 38 34 66 39 39 36 33 31 30 35 64 36 35 62 64 63 37 39 62 36 63 62 33 61 63 30 63 65 63 39 63 65 31 61 61 39”复制入数据发送框!然后点击连接,再点击发送。云端返回“20 02 00 00”!表示阿里云连接成功了!注意!100秒内将第二步的数据发给阿里云,否则阿里云将会自动断开连接的。


  第二步,我们尝试在阿里云订阅,发送和接收设置一定要为HEX,发送的数据为“82 25 00 0a 00 20 2F 61 31 44 6D 34 56 45 4B 38 42 52 2F 61 6C 69 79 75 6E 5F 64 65 76 2F 75 73 65 72 2F 4C 45 44 00”,如图6.2所示我们点击发送数据。云端返回“90 03 00 0A 01”!表示订阅成功了!注意!100秒内将第三步的数据发给阿里云,否则阿里云将会自动断开连接的。


  第三步,我们尝试取消第二步的订阅,发送和接收设置一定要为HEX,发送的数据为“a2 24 00 0a 00 20 2F 61 31 44 6D 34 56 45 4B 38 42 52 2F 61 6C 69 79 75 6E 5F 64 65 76 2F 75 73 65 72 2F 4C 45 44”,如图6.3所示我们点击发送数据。云端返回“B0 02 00 0A”,表示我们取消了第二步的订阅!注意!100秒内将第四步的数据发给阿里云,否则阿里云将会自动断开连接的。


  第四步,我们尝试发送消息给阿里云,发送和接收设置一定要为HEX,发送的数据为“30 98 01 00 35 2F 73 79 73 2F 61 31 44 6D 34 56 45 4B 38 42 52 2F 61 6C 69 79 75 6E 5F 64 65 76 2F 74 68 69 6E 67 2F 65 76 65 6E 74 2F 70 72 6F 70 65 72 74 79 2F 70 6F 73 74 7B 22 6D 65 74 68 6F 64 22 3A 22 74 68 69 6E 67 2E 65 76 65 6E 74 2E 70 72 6F 70 65 72 74 79 2E 70 6F 73 74 22 2C 22 69 64 22 3A 22 30 30 30 30 30 30 30 31 22 2C 22 70 61 72 61 6D 73 22 3A 7B 22 4C 45 44 53 77 69 74 63 68 22 3A 31 7D 2C 22 76 65 72 73 69 6F 6E 22 3A 22 31 2E 30 2E 30 22 7D”如图6.4所示发送成功!(阿里云不会返回数据的)

  至此,极速体验完成。如果想知道上述发送数据的含义和返回数据的含义,或者连接自己的阿里云,请看本文其它章节,上述操作的阿里云是作者本人的阿里云,将会长期有效,但并不一定永久有效的!

16.png
图6.1 连接阿里云
17.png
图6.2 阿里云订阅

18.png
图6.3 取消阿里云订阅

19.png
图6.4 发送消息给阿里云



正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

34

主题

322

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1838
金钱
1838
注册时间
2014-12-4
在线时间
717 小时
发表于 2021-7-6 16:55:23 | 显示全部楼层
回复 支持 反对

使用道具 举报

0

主题

24

帖子

0

精华

初级会员

Rank: 2

积分
87
金钱
87
注册时间
2020-5-23
在线时间
19 小时
发表于 2021-10-31 15:27:13 | 显示全部楼层
不明觉厉
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-9 15:03

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表