1. 前言
- 提到CoAP不能不提MQTT协议,MQTT协议可以保持长链接,具有一定的实时性,云端向客户端发送消息,设备端可以在最短的时间内接收并作出响应,所以MQTT更适合于实时控制场景,需要保持长连接,不停发送心跳报文,这就不会省电,不适用于低功耗场景。
- CoAP (Constrained Application Protocol)是受限制的应用协议的代名词,特点是低功耗,数据发完就可以休眠,所以CoAP更适合于数据采集的场合,由UDP承载,满足受限环境下M2M(Machine-to-Machine)的需求的协议。
2. CoAP协议报文
(1) Ver(Version) :协议版本号,占2个Bit
(2)T(Type) :报文数据类型,占2个Bit,CoAP协议有4种类型
-
①CON可确定报文(值为0)
接收端必须回复对应的ACK报文
,来通知是否准确拿到该消息。 -
②NON不确定报文(值为1)
不需要接收方返回ACK报文
-
③ACK响应报文(值为2)
ACK对应着上面的可确定报文 -
④Reset报文(值3)
在CoAP协议中,如果客户端每次协议发送都是不合格的,服务端认为该设备出现了不可描述的错误,可以通过Reset报文让其复位。
(3) TKL(Token Length):Token的长度,占4Bit,其作用喝消息ID是一致的,识别消息时使用,不适用该位置写0即可。
(4) Code(功能响应码):占1个字节,值为小数,前三位代表证书,后5位表示小数,包含4种类型,Get(0.01)、Post(0.02)、 Put(0.03)、DELETE(0.04),不涉及这个数位置,在使用过程中直接负责即可,0.01为0x01,0.02为0x02。
(5) Message ID(消息ID):消息ID可有自己指定,如果传输数据出现错误,服务器会返回错误的消息ID供你进一步处理。
(6)Token:如果TKL不为0,根据器长度,填写token值。
(7) Options(选配): 主要包含delta(增量)、length、和value三个部分选择,
- delta对应下面第二张图第一列的No.的增量
- length为数据长度,小于13(0xD)则直接填写,大于13则开启扩展一个字节,最多扩展2个字节(D扩充一个字节,E扩充2个字节),扩展之后,要减去13进行填写。
- value为数据的值。
(8) 0xFF:分割符
(9) pyaload:报文
2. 报文实战
本文基于中国电信天翼物联网AIoT平台进行实战
2.1 在物联网平台创建CoAP协议的产品与设备
具体操作流程可见平台操作手册
重点关注:
- 创建产品时,通信协议选择CoAP
- 创建产品时,“是否透传”,选择透传或者物模型,将对应不同的上下行报文格式。透传:平台对报文不进行解析,将报文透传给应用或终端;物模型:按照在平台定义的服务与属性,对上下行报文进行解析。
2.2 交互流程
2.3 报文内容提取
#结合创建的产品和交互流程,提取以下信息
POST
Host: 10401093.nb.ctwing.cn # ${租户ID}.nb.ctwing.cn
Port: 5682
Accept: application/octet-stream
Content-Format: application/octet-stream
payload: 空 # 登录为空,数据上报需要根据具体业务填写。
imei:234512345432123 # 创建设备时填写。
根据上述内容,
-
前四个字节帧格式为:0x40 02 00 01,分别代表,ver:1;Type:0(有ack);TKL:0;Code:0.02(post);消息ID:1
-
TKL为0,即Token为空
-
option:
注:根据平台交互接口说明,AIoT平台,并未将Uri-Host放入option中
(1)Uri_Path : 字节帧为0xB1740172,B代表Uri_Path的序号为11,1代表一个字节,74代表t的ASCII,01代表一个字节,72代表r的ASCII码
(2)Content_Format:字节帧为0x112A,第一个1代表基于Uri_Path,Content_Format的序号12的增量为1,第二个1代表一个字节,2A代表十进制42,代表Media Type:application/octet-stream,具体可见下面说明。
(3)Uri_Query:ep={endpointname},ep=234512345432123,字节帧为0x3D0565703d323334353132333435343332313233,3代表Uri_Query的增量为3,D代表扩展一个字节,05扩充一个字节后剩余长度为05(0x05+0xD=0x12)最后,将字节帧,拼接起来为:0x40020001B1740172112A3D0565703d323334353132333435343332313233
通过UDP通信协议发送出去
import socket
import binascii
# 创建UDP socket
client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 服务器地址
# 获取服务端主机与端口,可在设备管理->产品->产品概况中查看,如果是域名,可在本地ping一下获得IP
host = "180.109.255.252"
# 设置端口与服务器端一致
port = 5683
server_address = (host, port)
# 发送登录消息
payload = "40020001B1740172112A3D0565703d323334353132333435343332313233"
client.sendto(binascii.unhexlify(payload), server_address)
# 接收回应
response = binascii.hexlify(client.recv(1024)).decode("utf-8")
print(f"Received response: {response}")
# 关闭socket
client.close()
注:如有上报数据,则需要将报文转换成十六进制,作为payload进行上报。
参考文献:https://www.yuque.com/zhaotuantuan/wukixo/bqtm84