Chinaunix首页 | 论坛 | 博客
  • 博客访问: 615381
  • 博文数量: 49
  • 博客积分: 4153
  • 博客等级: 上校
  • 技术积分: 910
  • 用 户 组: 普通用户
  • 注册时间: 2007-12-25 16:40
文章分类

全部博文(49)

文章存档

2020年(3)

2012年(1)

2011年(1)

2010年(4)

2009年(37)

2008年(3)

分类: 其他平台

2020-09-16 09:37:27

阿里云MQTT设备的一型一密免白名单动态注册手册:

https://help.aliyun.com/document_detail/132111.html?spm=a2c4g.11186623.2.21.65461114YpNbOE#task-1545804


阿里云C-SDK下载手册:

https://help.aliyun.com/document_detail/96623.html?spm=a2c4g.11186623.2.16.3d122cf0tXDTVE


下面使用C-SDK的4.X版本进行设备的一型一密免白名单动态注册

首先是操作流程:

1. 在阿里云的产品端打开动态注册功能

2. 下载C-SDK 4.X版本至Ubunutu然后解压,下载参考上面的阿里云C-SDK下载手册

3. 打开demos/dynregmq_basic_demo.c文件进行编辑

4. 编辑main函数中的host字符串变量为自己产品的host路径$(ProductKey).iot-as-mqtt.cn-shanghai.aliyuncs.com

5. 编辑main函数中的product_key字符串为自己的$(ProductKey)

6. 编辑main函数中的product_secret字符串为自己的$(ProductSecret)

7. 编辑main函数中的device_name字符串为自己想要注册的设备名称,可以使用设备的MAC或者ID号作为设备之间的个体区分,这里为默认的dynreg_device_01

8. 编辑main函数中的nowhitelist变量,设置为1用于选择使用免白名单功能

9. 执行make进行编译

10. 执行./output/dynregmq-basic-demo即可运行


显示结果如下:

[1600074451.922][LK-0313] MQTT user calls aiot_mqtt_connect api, connect

establish mbedtls connection with server(host='x.iot-as-mqtt.cn-shanghai.aliyuncs.com', port=[443])

success to establish tcp, fd=3

success to establish mbedtls connection, fd = 3(cost 44958 bytes in total, max used 47870 bytes)

[1600074452.288][LK-0313] MQTT connect success in 360 ms

[1600074452.288][LK-0309] pub: /ext/regnwl

xxxx           

clientid: x|authType=connwl,securemode=-2,_ss=1,ext=3,_v=sdk-c-4.0.0|

username: x&x

password: x


执行完成后阿里云上的设备端则会生成dynreg_device_01这个设备,状态为未激活

设备的动态注册MQTT协议流程很简单:

1) 设备通过TLS加密发送CONNECT包(clientId部分携带动态注册信息,格式为$(DeviceName).$(ProductKey)|random=672753970,authType=regnwl,securemode=2,signmethod=hmacsha256|)给服务端建立会话

2) 设备接收CONNACK包确认会话的建立

3) 设备等待接收服务端发来的PUBLISH包(主题为"/ext/regnwl",负载部分携带clientId,productKey,deviceName,deviceToken)


下面是代码流程解析:

1.main

1) 通过aiot_sysdep_set_portfile函数设置SDK的底层接口操作句柄,这里设置为g_aiot_sysdep_portfile(包含网络,内存管理,互斥锁管理等接口)

2) 创建SDK的安全凭据, 用于建立TLS连接

3) 通过aiot_dynregmq_init函数创建1个dynregmq_handle_t实例并初始化默认参数

4) 配置会话的服务器地址,端口,productKey,productSecret,deviceName等信息至刚申请的dynregmq_handle_t结构体中,其中recv_handler配置为demo_dynregmq_recv_handler函数

5) 通过aiot_dynregmq_send_request函数发送CONNECT包进行动态设备的注册

6) 通过aiot_dynregmq_recv函数接收动态注册的PUBLISH回包

7) 通过aiot_dynregmq_deinit函数销毁申请的dynregmq_handle_t实例


2. aiot_dynregmq_send_request

1) 通过aiot_mqtt_init函数创建core_mqtt_handle_t实例并进行内部变量的初始化

2) 根据是否使用白名单选择clientId中authType的认证类型,这里使用免白名单模式则为connwl

3) 生成clientid, username和password用于之后的CONNECT包连接

4) 将之前创建的dynregmq_handle_t实例中配置的服务器地址,端口等信息拷贝至刚创建的core_mqtt_handle_t实例中,其中recv_handler配置为_dynregmq_recv_handler,userdata配置为刚之前创建的dynregmq_handle_t实例

5) 通过aiot_mqtt_connect函数进行会话的连接


3.aiot_mqtt_connect

1) 通过_core_mqtt_connect函数进行会话的连接

2) 如会话连接成功(接收到CONNACK包),则通过_core_mqtt_connect_event_notify函数进行CONNECT成功的事件通知,过程为先调用系统的event_handler回调函数进行处理,然后遍历process_data_list队列,将事件使用其handler回调函数进行处理


4._core_mqtt_connect

1) 通过core_sysdep_network_init函数句柄创建一个core_network_handle_t实例用于网络通信

2) 设置core_network_handle_t实例的socket类型为TCP_CLIENT,以及根据之前申请的core_mqtt_handle_t实例设置HOST地址,目标端口,连接超时时间,证书等配置

3) 通过core_sysdep_network_establish函数句柄进行网络的连接

4) 通过_core_mqtt_conn_pkt函数进行CONNECT包的构建

5) 通过_core_mqtt_write函数发送CONNECT包的内容

6) 通过_core_mqtt_read函数读取网络数据,这里读取的数据长度为CONNACK包的长度

7) 通过_core_mqtt_connack_handle函数检测收到的数据是否为CONNACK包


5. _core_mqtt_conn_pkt

1) 设置负载的长度为clientid,username,password 3个字符串的长度加上每个字符串2字节的长度标识(UTF-8格式)

2) 剩余长度为可变包头加负载的长度

3) 计算connect包的大小,其中剩余长度固定估算使用4字节

4) 设置固定包头的header字节CONNECT包的配置

5) 通过_core_mqtt_remain_len_encode函数计算剩余长度并对剩余长度字段赋值

6) 设置MQTT协议版本信息

7) 设置MQTT协议版本号

8) 设置CONNECT Flag标识

9) 设置KeepAlive字段

10) 设置负载的clientId内容,2字节长度加字符串长度

11) 设置负载的username内容,2字节长度加字符串长度

12) 设置负载的password内容,2字节长度加字符串长度


6._core_mqtt_connack_handle

1) 检查header,剩余长度和flag的值是否CONNACK包匹配,匹配则确认为CONNACK包,获取返回码

2) 根据CONNACK包的返回码返回CONNECT的结果


7.aiot_dynregmq_recv

1) 检测是否超过超时时间,超过则返回超时异常

2) 未超时则通过aiot_mqtt_recv函数接收MQTT包


8.aiot_mqtt_recv

1) 检查会话是否需要重新连接,如果需要则通过_core_mqtt_reconnect函数进行重连接

2) 通过_core_mqtt_read函数读取一个字节用于包的header类型解析

3) 通过_core_mqtt_read_remainlen函数读取剩余字节字段的数据

4) 根据剩余字节的信息通过_core_mqtt_read_remainbytes函数读取剩余字节

5) 获取header字节的packet type字段

6) 根据packet type类型,调用对应的处理,如果设备注册成功,则服务器返回PUBLISH包

7) 通过_core_mqtt_pub_handler函数处理接收到的PUBLISH包


9._core_mqtt_pub_handler

1) 设置包的类型为AIOT_MQTTRECV_PUB

2) 获取主题字符串

3) 检查QoS是否为QoS1,是则获取packetId

4) 获得负载数据

5) 如果QoS为QoS1则通过_core_mqtt_puback_send函数发送PUBACK包

6) 遍历sub_list订阅主题队列,匹配是否有主题和当前的PUBLISH包主题对应上,如果匹配上,则遍历主题节点的handle_list队列,将其节点复制一份挂载到handler_list_copy队列上

7) 遍历handler_list_copy队列,调用订阅主题的handler回调函数进行处理

8) 如果没有与订阅主题匹配上,则调用系统的默认回调函数recv_handler进行处理,这里为之前注册的_dynregmq_recv_handler


10._dynregmq_recv_handler

1) 判断传入的aiot_mqtt_recv_t包是否为AIOT_MQTTRECV_PUB类型

2) 是则判断其主题名称是否匹配我们使用的是免白名单注册字符串"/ext/regnwl"

3) 如果匹配则通过core_json_value函数对包的负载内容进行clientId和deviceToken的提取

4) 设置动态注册标志flag_completed为1标识成功完成设备的动态注册

5) 判断dynregmq_handle_t的recv_handler动态注册处理函数是否存在,之前配置了这个函数为demo_dynregmq_recv_handler

6) 存在则生成设备用于连接阿里云服务器的clientid,username和password存放于aiot_dynregmq_recv_t结构体中,并设置其type类型为AIOT_DYNREGMQRECV_DEVICEINFO_NWL表示免白名单动态注册,然后调用recv_handler,也就是demo_dynregmq_recv_handler


11.demo_dynregmq_recv_handler

1) 判断传入的aiot_dynregmq_recv_t结构体指针其type类型,这里为AIOT_DYNREGMQRECV_DEVICEINFO_NWL类型

2) 将传入的aiot_dynregmq_recv_t结构体的clientid,username,password拷贝至全局结构体变量demo_devinfo_nwl中进行长期保存


阅读(2194) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~