前言:
在文档中关键词会用红色标注,黑色字体更多的是举例和解释,快速了解关注红色字体即可
CoAP原版手册下载地址:https://pan.baidu.com/s/1MOvMn4VkobUrSfcbBQymMQ 提取码:l0ml
本文档出发点在于现有协议应用协议分析,仅供学习使用。
CoAP协议简述及应用场景
在物联网的数据道路上,避免不了接触各种各样的通信协议,不管是与服务器对接,边缘计算对接,我们想要处理的内容无疑都是数据,那么数据的传输就变得尤为重要,其中就包括了MQTT,HTTP,COAP等协议,本篇章将完成对CoAP协议的解析和示例代码演示。— 协议一通百通,最关键的要了解其使用用途和优势。
MQTT的特点是可以保持长连接,具有一定的实时性,云端向设备端发送消息,设备端可以在最短的时间内接收到并作出响应,所以MQTT更适合需要实时控制的场合,更适合执行器。要保持长连接,那么就要时不时地发送心跳包,这就不会省电了。所以低功耗的场合并不适合MQTT。MQTT的长连接需要建立在TCP的基础上,TCP协议的复杂性决定了对设备的要求是比较高一些的,相比UDP。
CoAP的特点是低功耗,数据发完就可以休眠了。所以CoAP更适合数据采集的场合,更适合纯粹的传感器设备,特别是电池供电的传感器设备。基于UDP协议,对设备的要求比较简单。华为出的NB-IoT芯片就只支持UDP和CoAP,华为的决策告诉我们CoAP和NB-IoT是一对。
| 协议 | 核心特点 | 下层协议 | 应用场合 | 硬件要求 |
|---|---|---|---|---|
| MQTT | 长连接 | TCP | 实时控制/执行器 | 较高 |
| CoAP | 低功耗 | UDP | 数据采集/传感器 | 较低 |
CoAP协议报文格式
Ver(Version):
在此内容中书写的是协议的版本号,占用两个Bit的空间,类似MQTT和HTTP中的版本号,填写指定数字即可,任何协议都需要考虑不同版本的支持,通过版本号的解析就可以从代码的角度做不同的处理,这一点让我们开发人员对软件开发不同的版本管理也能收获一丝丝灵感。
T(Type):
每一种协议都有很多种类的报文数据类型,CoAP比较简单,只有4种,占用两个Bit的空间,他们分别为:
①CON可确定报文(Confirmable 值 0):
前面说过,CoAP是基于UDP通信的可靠传输协议,为了确保数据的准确性必然要在交互上做文章,可确定报文一旦发出,接收端必须回复对应的ACK报文来通知是否准确的拿到了该消息,这里只需要记住,只要使用了可确定报文,接收端就必须返回一个ACK报文。
②NON不确定报文(Non-Confirmable 值 1):
懂了可确定报文,这个就更容易了,不确定报文就符合UDP通信了,发送方尽管发送接收方不做任何反应。类似微信官方发送的系统消息,你看不看都无所谓,反正我发了。在此协议中,不需要对方返回ACK报文。
③ACK响应报文(Acknowledgement 值 2):
④Reset报文 (值 3):
在CoAP中,如果每次协议发送都是不合格的,假设服务端需要接收数字1代表有效,但是客户端发了十次5,那么服务端可以认为该设备已经出现了不可描述的错误,可以通过Reset报文让其复位,重新运行,这就是Reset报文,当然这是软件层次上的,如果你的设备本身CoAP的消息都解析不出来,那只能人工去解决了。
TKL(Token Length):
Token的长度描述,占用4Bit的空间,其作用和消息ID是一致的,判断出错的消息使用,在正常使用中往往都不使用Token功能,直接使用消息ID即可,不使用该位置写0即可,当然做实验可以自己玩玩,Token Length的值是一个4位无符号整形数值,其直接影响后面的Token的数据长度,允许使用0 - 8字节。9 - 15字节为保留字节不允许发送,如果发送则认为错误数据。
Code(功能响应码):
功能响应码被定义成了4种类型,我们非常熟悉的HTTP中的4中操作,GET(值:0.01)、POST(值:0.02)、PUT(值:0.03)、DELETE(值:0.04)方法,在Code中,整体长度为1字节,值为小数,想要表示该值就需要看手册了,其实在规范中这1字节被分为了两部分,其中3位表示整数,5位表示小数。例:000(整数) . 00001(小数),则代表0.01,虽然看起来比较麻烦我们不如直接看值,无非就是1,2,3,4因为不涉及到整数的位置,在使用的过程中直接赋值即可,0.01就是0x01,0.02就是0x02以此类推,至于为什么这么设计就不得而知了,协议有时候就是这么玄幻,可能在某种特定版本中可以起到重要的作用。
Message ID(消息ID):
消息ID的值由你自己进行指定即可,如果传输数据出现错误,服务器会返回错误消息的ID供你进一步处理,对于我们写程序,每发送一次就 +1 就行了,如果不对错误判断,指定一个固定值也是可以的。
Options(选配):
此处是CoAP的重中之重,重要的数据参数全部都在这里了:
该位置的解释不如直接上示例(对接示例为阿里云)
①创建一个设备,满足ALINK协议(注册及使用过程参照MQTT说明对接文档)
②设备接入阿里云
既然是通信就一定要有验证加密等信息,在官方手册中提示到,发送数据之前先要进行设备验证,这一步相当于你拥有一把钥匙去打开一扇定时关闭的门,当你打开这扇门的时候可以进行数据的传递,当门关闭时需要重新开门,你可以把它看成某些网页的保存密码时长一样过期失效,但保存密码基本都是几天几个月,而这里可能就是几十或者几百秒而已。
下面的数据则是具体需要发送的内容,这里我们需要将其替换成我们自己的信息。假设信息为:
ProductKey:a1m57jiCuI2DeviceName:CoAP_testDeviceSecret:f22ee7dcad14ccebeba72de433db76dc
HmacMD5加密工具:http://tools.jb51.net/password/hash_encrypt
域名解析IP地址工具:http://ping.chinaz.com/
#将以上信息替换到这里POST /authHost: ${YourProductKey}.coap.${region}.link.aliyuncs.com#替换后,ProductKey用于区分设备,region用于服务器节点选择,这里选择的是上海,其他地区参考官方文档Host:a1m57jiCuI2.coap.cn-shanghai.link.aliyuncs.comPort: 5682Accept: application/jsonContent-Format: application/jsonpayload: {"productKey":"a1NUjcV****","deviceName":"ff1a11e7c08d4b3db2b1500d8e0e55","clientId":"a1NUjcV****&ff1a11e7c08d4b3db2b1500d8e0e55","sign":"F9FD53EE0CD010FCA40D14A9FE******", "seq":"10"}#替换后,根据阿里提供的信息填充即可,clientId:productKey&deviceName,sign通过DeviceSecret进行HmacMD5计算密码,加密内容:clientId###deviceName###productKey###seq### ,将###更换成自己的内容payload: {"productKey":"a1m57jiCuI2","deviceName":"CoAP_test","clientId":"a1m57jiCuI2&CoAP_test","sign":"5222804e7de3d37f1f7b172222560df7", "seq":"1"}
接下来,借助网络助手进行连接测试:<br /> 网络助手下载地址:[https://pan.baidu.com/s/1vlBSNfKtf1lomI3qnWYHSg](https://pan.baidu.com/s/1vlBSNfKtf1lomI3qnWYHSg) 提取码:tb3s <br /><br />根据上述内容,首先要发送验证包,方法为POST,帧格式为:0x40 02 00 01,分别代表,ver:1,Type:Post,TKL:0,Code:0.2,消息ID:1
Uri为:a1m57jiCuI2.coap.cn-shanghai.link.aliyuncs.com(提前站长工具将其转换成IP地址),此处封包的顺序按照下方详细图参照,0x3代表URL填充。
长度:长度的字节数是可变的,类似MQTT但是使用方式不一致,如果长度填写值低于13(0xD)则直接填写,如果大于13(0xD)则开启扩展1字节,如果值为14则扩展2字节,值为15无效。扩展之后的值,要减去13进行填写。
例:a1m57jiCuI2.coap.cn-shanghai.link.aliyuncs.com (46个字符,0x2E)
填写:0x3D 21 (3代表Option Delta,D代表13且扩展1字节,1字节填写剩余长度21,
总计0x21+0xD=0x2E)
Uri-Host数据则为:3D 21 61 31 6D 35 37 6A 69 43 75 49 32 2E 63 6F 61 70 2E 63 6E 2D 73 68 61 6E 67 68 61 69 2E 6C 69 6E 6B 2E 61 6C 69 79 75 6E 63 73 2E 63 6F 6D
继续向下填写,端口号,Option Delta的填写方式为增量填写,看下图,配置Port的NO.为7,之前配置成了3,那么7和3相差4,配置端口的方式则为0x4,从0x3增加0x4变成0x7,CoAP的规定。
例:5682 (0x1632)
填写:0x42 0x16 0x32 (0x4代表对3的增量实际值为0x7,0x2代表长度,0x16 0x32则代表数据)
继续向下填写,Uri-Path,Option Delta为11,继续增量如下:
例:/auth 为路径,不用管/符号。
填写:0x44 61 75 74 68 (0x4代表增量到11,0x4代表长度4,后面为auth 的ascii码)
继续向下填写Content-Format,格式内容后边的数据类型为uint类型,可以进行查询手册看看填写什么,手册截图如下:
例:Content-Format: application/json
填写:0x11 32 (0x1代表增量到12,1代表长度,32代表十进制50)
继续向下填写,Accept,同样是一个uint类型,查看上图即可:
例:Accept: application/json
填写:0x51 32 (0x5代表增量到17,1代表长度,32代表十进制50)

上图中回顾整体帧格式,在配置完Options之后,用0xff进行分割之后的Payload,那么直接填写即可。
数据为: {“productKey”:”a1m57jiCuI2”,”deviceName”:”CoAP_test”,”clientId”:”12345”,”sign”:”d790788a101ccdc0becb8cefb0e27519”, “seq”:”1”} 转换成16进制:7B 22 70 72 6F 64 75 63 74 4B 65 79 22 3A 22 61 31 6D 35 37 6A 69 43 75 49 32 22 2C 22 64 65 76 69 63 65 4E 61 6D 65 22 3A 22 43 6F 41 50 5F 74 65 73 74 22 2C 22 63 6C 69 65 6E 74 49 64 22 3A 22 31 32 33 34 35 22 2C 22 73 69 67 6E 22 3A 22 64 37 39 30 37 38 38 61 31 30 31 63 63 64 63 30 62 65 63 62 38 63 65 66 62 30 65 32 37 35 31 39 22 2C 20 22 73 65 71 22 3A 22 31 22 7D
最后进行数据整合:
协议头: 40 02 00 01
Options:3D 21 61 31 6D 35 37 6A 69 43 75 49 32 2E 63 6F 61 70 2E 63 6E 2D 73 68 61 6E 67 68 61 69 2E 6C 69 6E 6B 2E 61 6C 69 79 75 6E 63 73 2E 63 6F 6D
42 16 32
44 61 75 74 68
11 32
51 32
数据分割: FF
Payload: 7B 22 70 72 6F 64 75 63 74 4B 65 79 22 3A 22 61 31 6D 35 37 6A 69 43 75 49 32 22 2C 22 64 65 76 69 63 65 4E 61 6D 65 22 3A 22 43 6F 41 50 5F 74 65 73 74 22 2C 22 63 6C 69 65 6E 74 49 64 22 3A 22 61 31 6D 35 37 6A 69 43 75 49 32 26 43 6F 41 50 5F 74 65 73 74 22 2C 22 73 69 67 6E 22 3A 22 35 32 32 32 38 30 34 65 37 64 65 33 64 33 37 66 31 66 37 62 31 37 32 32 32 32 35 36 30 64 66 37 22 2C 20 22 73 65 71 22 3A 22 31 22 7D 
分析接收报文:60 45 00 01 FF 7B 22 72 61 6E 64 6F 6D 22 3A 22 38 37 38 39 34 34 66 62 37 62 38 34 63 32 39 62 22 2C 22 73 65 71 4F 66 66 73 65 74 22 3A 33 2C 22 74 6F 6B 65 6E 22 3A 22 55 53 30 49 54 7A 51 6A 62 65 32 67 59 69 33 74 6B 38 35 35 30 30 30 30 30 30 2E 31 31 39 64 22 7D
其中60 45 代表ver - code,00 01代表消息ID,FF后面则是数据,这里面只需要关心60 45,其他暂不关心。
转换二进制:
ver t TKL code
01 10 0000 010.00101
版本号:01
类型: ACK
TKL: 无
CODE: 2.05
Paylod转换成字符:{“random”:”878944fb7b84c29b”,”seqOffset”:3,”token”:”US0ITzQjbe2gYi3tk855000000.119d”}
该参数中的random,token等内容则是对之后上报数据进行加密使用的,在下边内容详解。
③上报数据
上行数据的方式同样在阿里云平台进行了解释,如果是初学者建议对照此文档和官方文档去看,这样更有助于之后的开发与对接研究,点击查看官方文档,如果急于开发迅速上手,直接看此文档即可。此文档注重实践与理论结合,开发主要关注红色字体,黑色字体为描述和比喻解释内容。

