NB-IoT 学习开发和应用 第四讲
阿里云物联网平台中的CoAP协议学习和分析
CoAP协议:CoAP协议的底层协议是 UDP (比喻:打电话,单方通信,无需保持链接)
应用范围: NB-IoT、超低功耗应用、野外数据采集监控系统、远程抄表等
特点 :只能数据上报(注:在CoAP协议的定义中,非底层的UDP协议),服务器无法对数据进行下发控制指令。
CoAP协议报文(一共只有4个)
分别是:
1、CON报文(连接请求报文),给服务器发报文,并且发送完以后,服务器必须要发送ACK报文给设备端(即响应报文)
2、NON报文(发送给服务器,服务器无需回复)
3、ACK报文 (响应报文)
4、RST报文(代表数据发送错误,提醒用户重新发送正确的数据给服务区)
注:且在阿里云物联网平台中的的CoAP协议中,只支持 CON报文的数据类型。其他数据格式或者协议,服务器均不支持。
同时,在阿里云物联网服务器中,上传的数据有两种形式(CON的两种形式)
1、设备认证报文
2、数据上传报文
CoAP协议报文的格式组成形式:
Ver+T+TKL+Code+Messige ID+Token+Options+0xff(分隔字符)+Payload
拆分分析:
Ver : 版本号 2bit
T : 报文类型 2bit (CON : 00 NON : 01 ACK : 10 RST : 11 )
TKL : 表示标识符(Token)的长度 4bit,Token在报文种是非必须的
Code :功能响应码 (共有四种 GET、POST、 PUSH、 DELETE)8bit
0.01 0.02 0.03 0.04
注:Code一个是8个bit(一个字节),前三位表示整数,后五位表示小数。
Message ID:报文编号消息编号,一般来说,每发一次Message ID加1.(数据标记)
Token :(可不要,在阿里云中我们默认不添加Token报文)
Options :数据选择模式
0xff : 间隔符(用于分离上传格式和数据)
Pyload :上传的数据
在上述讲解之前需要在此之前创建设备,获取阿里云的三元组
阿里云平台下的设备的三个基本参数:
{
"ProductKey": "a125zR8hwQq",
"DeviceName": "D001",
"DeviceSecret": "TmRnTWVOWjTPgqNIsVwcLqRInIQ9NFvn"
}
在阿里云物联网的开发文档中详细讲解了CoAP协议中上报数据的格式(注:这里使用使用对称加密自主接入(软件加密),阿里云物联网平台还有一种硬件加密(叫:DTLS加密)形式。)
在:阿里云物联网CoAP协议说明
同时,可以看到有以下两种报文的上传的数据格式
分别是:
1、阿里云设备认证请求报文:
格式数据如下
POST /auth
Host: ${YourProductKey}.coap.cn-shanghai.link.aliyuncs.com
Port: 5682
Accept: application/json or application/cbor
Content-Format: application/json or application/cbor
payload: {"productKey":"a1NUjcV****","deviceName":"ff1a11e7c08d4b3db2b1500d8e0e55","clientId":"a1NUjcV****&ff1a11e7c08d4b3db2b1500d8e0e55","sign":"F9FD53EE0CD010FCA40D14A9FE******", "seq":"10"}
所以我们在终端需要构建上述的报文格式(我们构建报文的形式是以CoAP协议的数据格式进行构建,这样在云服务器就能够解析我们发送的数据)
我们在构建是需要以:
CoAP协议报文的格式组和形式:
Ver+T+TKL+Code+Messige ID+Token+Options+0xff(分隔字符)+Payload
(注:以上的每个代表的含义在上方已经定义,可往上进行阅览)
首先是:
Ver : 01
T :00 (CON : 00 NON : 01 ACK : 10 RST : 11 )
TKL : 0000 (默认不用Token数据,所以数据长度为0)
Code : 000.00010 (GET:0.01 POST:0.02 PUSH:0.03 DELETE : 0.04)
Message ID ;0x?? 0x??(消息编号,建议,可以从0x00 0x00 开始,没上传(post)一条报文(消息)就加1 )
Token :可以省略不写(无数据)
- 这样上面转换成16进制就是 : 0x40 0x02 0x01 0x01
接下来就是Options的数据组成形式:
在阿里云阿里云设备认证请求报文中:即
POST /auth
Host: ${YourProductKey}.coap.cn-shanghai.link.aliyuncs.com
Port: 5682
Accept: application/json or application/cbor
Content-Format: application/json or application/cbor
payload: {"productKey":"a1NUjcV****","deviceName":"ff1a11e7c08d4b3db2b1500d8e0e55","clientId":"a1NUjcV****&ff1a11e7c08d4b3db2b1500d8e0e55","sign":"F9FD53EE0CD010FCA40D14A9FE******", "seq":"10"}
除了payload以外,以上的全是在options中进行数据的组合
Options : 由option-delta (4个bit) 和option length(4个bit 或者再增加一个字节到两个字节来表示后面字符的长度)
options : 0011 ???(表示后续字节的长度),如果单独用4bit位来表示长度,那么最大位1100(十进制的12),如果是(1101)(十进制的13)则代表的是后面再扩展一个字节来表示数据的长度,后面的那个字节的长度=实际长度-13
如果是(1110)(十进制的14)则代表的是后面再扩展2个字节来表示数据的长度,后面的那个字节的长度=实际长度-14-255 (用两个字节来表示剩余长度)
首先是:
Host: ${YourProductKey}.coap.cn-shanghai.link.aliyuncs.com (HOST 指令是用3来表示)
option delta 表示发送的option的增量,(因为每一个指令有不同的序列号来表示),代表的是不同的数据增量。
options : 0011 ???(表示后续字节的长度),如果单独用4bit位来表示长度,那么最大位1100(十进制的12),如果是(1101)(十进制的13)则代表的是后面再扩展一个字节来表示数据的长度,后面的那个字节的长度=实际长度-13
如果是(1110)(十进制的14)则代表的是后面再扩展2个字节来表示数据的长度,后面的那个字节的长度=实际长度-14-255 (用两个字节来表示剩余长度)
首先是:
Host: a125zR8hwQq.coap.cn-shanghai.link.aliyuncs.com (HOST 指令是用3来表示,这是第一个指令,所以delta=3-0=3)
所以:0011 ???(注:4个问号代表的是后面数据长度,即" a125zR8hwQq.coap.cn-shanghai.link.aliyuncs.com "的长度是46,所以需要额外增加一个字节的长度,这样 ????=1101=D(16进制),后面跟的字节=46-13=33=0x21)
总的第一个字节就是 : 0x3D
后面的1个字节是: 0x21
最后的字节是:(a125zR8hwQq.coap.cn-shanghai.link.aliyuncs.com)的16进制数
总的后面的字节是:
0x3D 0x21 +(a125zR8hwQq.coap.cn-shanghai.link.aliyuncs.com)16进制
接下来是
Port : 5682 (前面的Host 是指令3 Port 是指令 7 ,所以delta=7-3=4)
所以: 0100 ???? (5682的十六进制是两个字节,固????= 0010)
总的第一个字节就是 : 0x42
后面的两个字节是: 0x16 0x32(5682的16进制=0x1632)
总的后面字节是:
0x42 0x16 0x32
随后是:
POST /auth (前面的Port是指令7 Path(也就是post) 是指令 11 ,所以delta=11-7=4)
所以: 0100 ????(auth就是4个字节,????=0100)
总的第一个字节就是 : 0x44
后面的4个字节是: 0x61 0x75 0x74 0x68("auth"的16进制,注:斜杠不属(不计入)于字符)
总的字节是:
0x44 + 0x61 0x75 0x74 0x68("auth"的16进制,注:斜杠不属(不计入)于字符)
在后来是:
Content-Format: application/json or application/cbor
(前面的POST是指令1 Content-Format是指令 12 ,所以delta=12-11=1)
所以: 0001 ????(application/json or application/cbor在CoAP中有对应的指令为,所以这里????=0001 ,因为50的十六进制是0x32,也就是后面的长度是1)
总的第一个字节就是 : 0x11
后面的1个字节是: 0x32
总的字节是: 0x11 0x32
Accept: application/json or application/cbor
(前面的Content-Format是指令12 Accept是指令 17 ,所以delta=17-12=5)
所以: 0101 ????(application/json or application/cbor在CoAP中有对应的指令为,所以这里????=0001 ,因为50的十六进制是0x32,也就是后面的长度是1)
总的第一个字节就是 : 0x51
后面的1个字节是: 0x32
这样options的参数就全部完成了,接下来则还剩下分隔符和payload的数据了
分隔符 :(隔离)
0xff
payload:{“productKey”:“a125zR8hwQq”,“deviceName”:“ff1a11e7c08d4b3db2b1500d8e0e55”,“clientId”:“a125zR8hwQq&ff1a11e7c08d4b3db2b1500d8e0e55”,“sign”:“F9FD53EE0CD010FCA40D14A9FE******”, “seq”:“10”} (调试发送时,变成16进制便于发送)
{
“ProductKey”: “a125zR8hwQq”,
“DeviceName”: “D001”,
“DeviceSecret”: “TmRnTWVOWjTPgqNIsVwcLqRInIQ9NFvn”
}
返回数据:
{"random":"ad2b3a5eb51d6****","seqOffset":1,"token":"MZ8m37hp01w1SSqoDFzo001050****.ad2b"}
但是在16进制中看到的数据时这样的
发送后会得到回复数据:
0x60 0x45 (表示接收的是正确请求,否则出现错误)
0xff
0x?? ... (一堆的加密的密钥等其他数据,就是上述{random:“xxx...."等这些数据)
由上面即可得到:上述这些即可实现设备认证请求。
2、阿里云数据上报数据请求:
数据格式如下:
POST /topic/${topic}
Host: ${YourProductKey}.coap.cn-shanghai.link.aliyuncs.com
Port: 5682
Accept: application/json or application/cbor
Content-Format: application/json or application/cbor
payload: ${your_data}
CustomOptions: number:2088(标识token), 2089(seq)
替换更改后的数据是:
POST /topic//sys/a1P71zSMssS/D001/thing/event/property/post
Host: a125zR8hwQq.coap.cn-shanghai.link.aliyuncs.com
Port: 5682
Accept: application/json or application/cbor
Content-Format: application/json or application/cbor
payload: ${your_data}
CustomOptions: number:2088(标识token), 2089(seq)
开始构建数据上传报文:
CoAP协议报文的格式组和形式:
Ver+T+TKL+Code+Messige ID+Token+Options+0xff(分隔字符)+Payload
(注:以上的每个代表的含义在上方已经定义,可往上进行阅览)
首先是:
Ver : 01
T :00 (CON : 00 NON : 01 ACK : 10 RST : 11 ,注:阿里云CoAP协议中只支持 CON 格式)
TKL : 0000 (默认不用Token数据,所以数据长度为0)
Code : 000.00010 (GET:0.01 POST:0.02 PUSH:0.03 DELETE : 0.04)
Message ID ;0x?? 0x??(消息编号,建议,可以从0x00 0x00 开始,没上传(post)一条报文(消息)就加1 )
Token :可以省略不写(无数据)
- 这样上面转换成16进制就是 : 0x40 0x02 0x01 0x01
首先是:
Host: a125zR8hwQq.coap.cn-shanghai.link.aliyuncs.com (HOST 指令是用3来表示,这是第一个指令,所以delta=3-0=3)
所以:0011 ???(注:4个问号代表的是后面数据长度,即" a125zR8hwQq.coap.cn-shanghai.link.aliyuncs.com "的长度是46,所以需要额外增加一个字节的长度,这样 ????=1101=D(16进制),后面跟的字节=46-13=33=0x21)
总的第一个字节就是 : 0x3D
后面的1个字节是: 0x21
最后的字节是:(a125zR8hwQq.coap.cn-shanghai.link.aliyuncs.com)的16进制数
总的后面的字节是:
0x3D 0x21 +(a125zR8hwQq.coap.cn-shanghai.link.aliyuncs.com)16进制
接下来是
Port : 5682 (前面的Host 是指令3 Port 是指令 7 ,所以delta=7-3=4)
所以: 0100 ???? (5682的十六进制是两个字节,固????= 0010)
总的第一个字节就是 : 0x42
后面的两个字节是: 0x16 0x32(5682的16进制=0x1632)
总的后面字节是:
0x42 0x16 0x32
接下来就是Options的数据组成形式:
在阿里云阿里云设备认证请求报文中:即
POST /topic//sys/a1P71zSMssS/D001/thing/event/property/post
Host: a125zR8hwQq.coap.cn-shanghai.link.aliyuncs.com
Port: 5682
Accept: application/json or application/cbor
Content-Format: application/json or application/cbor
payload: ${your_data}
CustomOptions: number:2088(标识token), 2089(seq)
除了payload以外,以上的全是在options中进行数据的组合
Options : 由option-delta (4个bit) 和option length(4个bit 或者再增加一个字节到两个字节来表示后面字符的长度)
options : 0011 ???(表示后续字节的长度),如果单独用4bit位来表示长度,那么最大位1100(十进制的12),如果是(1101)(十进制的13)则代表的是后面再扩展一个字节来表示数据的长度,后面的那个字节的长度=实际长度-13
如果是(1110)(十进制的14)则代表的是后面再扩展2个字节来表示数据的长度,后面的那个字节的长度=实际长度-14-255 (用两个字节来表示剩余长度)
首先是:
Host: a125zR8hwQq.coap.cn-shanghai.link.aliyuncs.com (HOST 指令是用3来表示,这是第一个指令,所以delta=3-0=3)
所以:0011 ???(注:4个问号代表的是后面数据长度,即" a125zR8hwQq.coap.cn-shanghai.link.aliyuncs.com "的长度是46,所以需要额外增加一个字节的长度,这样 ????=1101=D(16进制),后面跟的字节=46-13=33=0x21)
总的第一个字节就是 : 0x3D
后面的1个字节是: 0x21
最后的字节是:(a125zR8hwQq.coap.cn-shanghai.link.aliyuncs.com)的16进制数
总的后面的字节是:
0x3D 0x21 +(a125zR8hwQq.coap.cn-shanghai.link.aliyuncs.com)16进制
接下来是
Port : 5682 (前面的Host 是指令3 Port 是指令 7 ,所以delta=7-3=4)
所以: 0100 ???? (5682的十六进制是两个字节,固????= 0010)
总的第一个字节就是 : 0x42
后面的两个字节是: 0x16 0x32(5682的16进制=0x1632)
总的后面字节是:
0x42 0x16 0x32
(注:在设备认证和数据上传中,以上是通用的数据模型)
POST /topic/{topic} 中的${topic}替换为 /sys/a1P71zSMssS/D001/thing/event/property/post
替换后的是: /topic /sys/a1P71zSMssS/D001/thing/event/property/post
又因为后面一共将路径分成了多个小节,在CoAP协议中需要单独的进行统计来计算
故:
对于第一个字符串 topic 后的表示
的第一个字节是 :0x45 (前面的Port是指令7 Path(也就是post) 是指令 11 ,所以delta=11-7=4)
总的后面跟随的5个字节就是 : 74 6F 70 69 63 ("topic"的16进制)
对于第2个字符串 sys后的表示
的第一个字节是 :0x03 (前面的Path是指令11 Path(也就是post)也 是指令 11 ,所以delta=11-11=0)
总的后面跟随的3个字节就是 : 73 79 73 ("sys"的16进制)
对于第3个字符串 a1P71zSMssS后的表示
的第一个字节是 :0x0B (前面的Path是指令11 Path(也就是post)也 是指令 11 ,所以delta=11-11=0)
总的后面跟随的11个字节就是 :61 31 50 37 31 7A 53 4D 73 73 53 ("a1P71zSMssS"的16进制)
对于第4个字符串 D001后的表示
的第一个字节是 :0x04 (前面的Path是指令11 Path(也就是post)也 是指令 11 ,所以delta=11-11=0)
总的后面跟随的4个字节就是 :44 30 30 31 ("D001"的16进制)
对于第5个字符串 thing后的表示
的第一个字节是 :0x05 (前面的Path是指令11 Path(也就是post)也 是指令 11 ,所以delta=11-11=0)
后面的5个字节是: 74 68 69 6E 67 ("thing"的16进制,注:斜杠不属(不计入)于字符)
对于第6个字符串 event后的表示
的第一个字节是 :0x05 (前面的Path是指令11 Path(也就是post)也 是指令 11 ,所以delta=11-11=0)
后面的5个字节是: 65 76 65 6E 74 ("event"的16进制,注:斜杠不属(不计入)于字符)
对于第7个字符串 property后的表示
的第一个字节是 :0x08 (前面的Path是指令11 Path(也就是post)也 是指令 11 ,所以delta=11-11=0)
后面的8个字节是: 70 72 6F 70 65 72 74 79 ("property"的16进制,注:斜杠不属(不计入)于字符)
对于第8个字符串 post后的表示
的第一个字节是 :0x04 (前面的Path是指令11 Path(也就是post)也 是指令 11 ,所以delta=11-11=0)
后面的4个字节是: 70 6F 73 74 ("post"的16进制,注:斜杠不属(不计入)于字符)
接下来是:
Content-Format: application/json or application/cbor
(前面的POST是指令1 Content-Format是指令 12 ,所以delta=12-11=1)
所以: 0001 ????(application/json or application/cbor在CoAP中有对应的指令为,所以这里????=0001 ,因为50的十六进制是0x32,也就是后面的长度是1)
总的第一个字节就是 : 0x11
后面的1个字节是: 0x32
Accept: application/json or application/cbor
(前面的Content-Format是指令12 Accept是指令 17 ,所以delta=17-12=5)
所以: 0101 ????(application/json or application/cbor在CoAP中有对应的指令为,所以这里????=0001 ,因为50的十六进制是0x32,也就是后面的长度是1)
总的第一个字节就是 : 0x51
后面的1个字节是: 0x32
最后是:
CustomOptions: number:2088(标识token), 2089(seq)
(前面的Accep是指令17 CustomOptions(阿里云定义的)是指令 2088 ,所以delta=2088-17=2071)
所以: 1110 ????(0xE?,这里的0xD? 中的D是14,所以需要两个字节来表示指令的增量,所以后面两个字节的=2088-17-14-255==0x07 0x0A)
在这后面还跟了设备认证后下发的字符串(token字符串),一共31个字节,所以前面的0XE?中的 ?是D,后面接了31个token认证的字符串 是31-13=18,也就是0x12)
0x?? 。。。(31个)
总的就是: 0xDE 0X07 0X0A 0x12
0x?? …("hUJL2bcEHxkPvRwKR5Pq000100.3a2d"31个字符的16进制)
CustomOptions: number:2088(标识token), 2089(seq)
(前面 的CustomOptions(阿里云定义的)是指令 2088 CustomOptions(阿里云定义的)是指令 2089(seq),所以delta=2089-2088=1)
所以: 0001 1101(0x1D,注:后面seq加密后字符串长度是固定的16个,所以后面还需要一个字节来表示长度16-13=3 )
即:0x03
最后 : 0x??(一共16个)
这样options的参数就全部完成了,接下来则还剩下分隔符和payload的数据了
分隔符 :(隔离)
0xff
payload:{“productKey”:“a125zR8hwQq”,“deviceName”:“ff1a11e7c08d4b3db2b1500d8e0e55”,“clientId”:“a125zR8hwQq&ff1a11e7c08d4b3db2b1500d8e0e55”,“sign”:“F9FD53EE0CD010FCA40D14A9FE******”, “seq”:“10”} (调试发送时,变成16进制便于发送)
这样就完成了数据上报了
三元组
{
“ProductKey”: “a1P71zSMssS”,
“DeviceName”: “D001”,
“DeviceSecret”: “gWRyTGu2gmgUuylSwT0Z53IA8fWqsRSE”
}
{ “random”:“8894acb651b09d67”,“seq0ffest”:“2”,“token”:“hUJL2bcEHxkPvRwKR5Pq000100.3a2d”}
最后:对于
2089(AES加密项)
1)构建明文: DeviceSecret,+第一步认证时返回的random字符串
eg: gWRyTGu2gmgUuylSwT0Z53IA8fWqsRSE,8894acb651b09d67
2) 对 明文进行 SHA256编码,得到的结果时32个字节(字符),去掉前面8个,去掉后面8个,保留中间的16个。
4c 70 8a 88 9e 62 0b 60 (舍去)
98 ab dc 1f 61 5a bc 11 a6 62 49 18 3d 4a 18 (实际用的密钥)
6b ad a0 21 60 bc b7 1c (舍去)
3)进行AES加密,加密的初始向量是 : 35343379686A79393761653766796667
明文: 33(和seq0ffest中获取的值要不一致,且要比该数字要大)
4)使用AES加密工具得到AES的结果放置在2089报文的后面
5)Payload 的数据也要作为明文进行加密后放到0xff(分隔符)后面
来源:CSDN
作者:没有价值的生命
链接:https://blog.csdn.net/lj1986817902/article/details/104475838