教你动手写UDP协议栈系列文章
序号 | 内容 |
---|---|
1 | 《教你动手写UDP协议栈-UDP协议栈格式》 |
2 | 《教你动手写UDP协议栈-DHCP报文解析》 |
3 | 《教你动手写UDP协议栈-OTA上位机》 |
4 | 《教你动手写UDP协议栈-DNS报文解析》 |
4 | 《教你动手写UDP协议栈-CoAP报文解析 |
背景
- CoAP(Constrained Application Protocol),它属于网络协议栈中应用层协议,它使那些被称为“节点”的受限设备能够使用类似的协议与更广泛的互联网进行通信。CoAP设计用于同一受限网络(例如低功耗、有损网络)上的设备之间、Internet上的设备和一般节点之间,以及通过Internet连接的不同受限网络上的设备之间。
- 在之前的文章中,描述了采用UDP进行OTA,而当时的UDP-OTA局限于本地OTA。而对于物联网设备,不可能每次升级都跑到设备旁边进行本地OTA吧,所以需要进行远程OTA。
CoAP
CoAP协议特点
- CoAP协议网络传输层是采用UDP。
- 非加密CoAP协议层如下:
----------------------
| Application |
----------------------
| Requests/Responses |
----------------------
| Messages |
----------------------
| UDP |
----------------------
- 加密CoAP协议层如下:
----------------------
| Application |
----------------------
| Requests/Responses |
----------------------
| Messages |
----------------------
| DTLS |
----------------------
| UDP |
----------------------
- CoAP它是基于REST软件架构,CoAP是类HTTP协议,它是对HTTP协议简化,server的资源地址和互联网一样也有类似url的格式,客户端同样有POST,GET,PUT,DELETE方法来访问server。
- CoAP协议是采用二进制格式,而HTTP协议是文本格式,所以CoAP比HTTP协议更加紧凑。
- Coap协议是一个轻量化协议,最小长度仅仅为4B。
- 支持可靠传输,数据重传,块传输。确保数据可靠到达,异步通信。
- 支持IP多播, 即可以同时向多个设备发送请求。
- 非长连接通信,适用于低功耗物联网场景。
CoAP报文格式
代码语言:javascript复制 2 2 4 8 16
--- --- ----- ---------------- ---------------------------|
|ver| T | TKL | Code | Message ID |
----------------------------------------------------------|
| Token(if any, TKL bytes)... |
----------------------------------------------------------|
| Optons(if any)... |
--------------- ------------------------------------------|
|1 1 1 1 1 1 1 1| Payload(if any)... |
----------------------------------------------------------|
- 消息头部(如上:第一行是消息头,固定4个byte)
字段 | 大小 | 说明 |
---|---|---|
ver | 2bit | 版本信息,当前必须写0x01 |
T | 2bit | 消息类型,包括CON,NON,ACK,RST.4种 |
TKL | 4bit | token长度,支持0~8Byte长度,其他长度保留将来扩张用。token对报文来说是非必须的 |
Code | 1byte | 分成前3bit(0~7)和后5bit(0~31),前3bit代表类型(class type), 后5bit代表细节码(detail code),为了方便描述写成c.dd结构 |
Message ID | 2byte | 报文编号,每个报文都有一个ID ,重发的消息ID不变 |
Token | 0~8byte | 可选,用于将响应与请求匹配。每个请求都带有一个客户端生成的token, 服务器在任何结果响应中都必须对其进行回应。token类似消息ID,用以标记消息的唯一性。token还是消息安全性的一个设置,使用全8字节的随机数,使伪造的报文无法获得验证通过。 |
Option | ~ | 请求消息 与回应消息都可以0~多个options。主要用于描述请求或者响应对应的各个属性,类似参数或者特征描述,比如是否用到代理服务器,目的主机的端口等。 |
Payload | ~ | 实际携带数据内容,若有,前面加payload标识符“0xFF”,如果没有payload标识符,那么就代表这是一个0长度的payload。如果存在payload标识符但其后跟随的是0长度的payload,那么必须当作消息格式错误处理。 |
CoAP协议消息类型
- CoAP协议分为4种消息类型
- CON:需要被确认请求,如果CON请求被发送,那么对方必须做出响应。这种方式有点类似TCP,用于可靠消息传输。模型如下图:
Client Server
| CON[0x7d34] |
---------------->|
| ACK[0x7d34] |
<----------------|
| |
- NON:不需要被确认的请求,如果NON请求被发送,那么对方不必做出回应。这适用于消息会重复频繁的发送,丢包不影响正常操作。这种方式有点类似UDP,用以不可靠消息传输。模型如下图:
Client Server
| NON[0x01a0] |
---------------->|
| |
- ACK:应答消息,接受到CON消息的响应。
- RST:复位消息,当接收者接收到的消息包含一个错误或者不认识消息,接受者不能回ACK消息,必须回RST消息。
CoAP的请求码(requests)和响应码(responses)
- CoAP的请求码和响应码既是CoAP协议中Code字段,类似HTTP协议中的状态码。其中:
- 0.XX 表示CoAP请求的某种方法。
- 2.XX、4.XX、5.XX 表示CoAP响应的具体表现。
- 请求码(0.XX)
请求码 | 说明 |
---|---|
[0.01] | GET:用于获取某资源 |
[0.02] | POST:用于创建某资源 |
[0.03] | PUT:用于更新某资源 |
[0.04] | DELETE:用于删除某资源 |
- 响应码(2.XX):成功码
- 这一类型的状态码,代表请求已成功被服务器接收、理解、并接受。
请求码 | 说明 |
---|---|
[2.01] | Create:响应POST和PUT方法,不能缓存 |
[2.02] | Delete:响应POST和DELETE方法,不能缓存 |
[2.03] | Valid:用于响应request中Etag指定的response是有效的,不能包含payload |
[2.04] | Changed:响应POST和PUT方法,不能缓存 |
[2.05] | Content:响应GET方法,有缓存 |
- 响应码(4.XX):客户端错误码
- 这类的状态码代表了客户端看起来可能发生了错误,妨碍了服务器的处理。
请求码 | 说明 |
---|---|
[4.00] | Bad Request:请求错误,服务器无法处理。类似于HTTP 400 |
[4.01] | Unauthorized:没有范围权限。类似于HTTP 401 |
[4.02] | Bad Option:请求中包含错误选项 |
[4.03] | Forbidden:服务器拒绝请求。类似于HTTP 403 |
[4.04] | Not Found:服务器找不到资源。类似于HTTP 404 |
[4.05] | Method Not Allowed:非法请求方法。类似于HTTP 405 |
[4.06] | Not Acceptable:请求选项和服务器生成内容选项不一致。类似于HTTP 406 |
[4.12] | Precondition Failed:请求参数不足。类似于HTTP 412 |
[4.15] | Unsuppor Conten-Type:请求中的媒体类型不被支持。类似于HTTP 415 |
- 响应码(5.XX): 服务器错误码
- 这类状态码代表了服务器在处理请求的过程中有错误或者异常状态发生,也有可能是服务器的软硬件资源无法完成对请求的处理。
请求码 | 说明 |
---|---|
[5.00] | Internal Server Error:服务器内部错误。类似于HTTP 500 |
[5.01] | Not Implemented:服务器无法支持请求内容。类似于HTTP 501 |
[5.02] | Bad Gateway:服务器作为网关时,收到了一个错误的响应。类似于HTTP 502 |
[5.03] | Service Unavailable:服务器过载或者维护停机。类似于HTTP 503 |
[5.04] | Gateway Timeout:服务器作为网关时,执行请求时发生超时错误。类似于HTTP 504 |
[5.05] | Proxying Not Supported:服务器不支持代理功能 |
CoAP的可选字段(Option)
- CoAP支持多个Option,CoAP的Option的表示采用增量的方式描述。Option的属性如下几类:
- Critical Option:接收方必须能够理解的Option,否则消息无法正常处理。
- Elective Option:接收方不识别该Option时,可以忽略,不影响消息的正常处理。
- Unsafe Option:Proxy不识别不能转发其所在的Message的Option,并不是每个Critical Option都是Unsafe Option。
- Safe-to-Forward Option:Proxy不识别仍可转发其所在的Message的Option
- CoAP 的Option格式:
-------------- ---------------
| option delta | option length | 1 byte
------------------------------
option delta
/ (extended) / 0 ~ 2 byte
------------------------------
option length
/ (extended) / 0 ~ 2 byte
------------------------------
/ /
option Value 0 or more bytes
/ /
------------------------------
- CoAP 的Option格式描述:
- Option Delta:
- Option在message中的实例必须按照编号大小顺序存放,Option的实际编号由本Option中Delta值 上一个Option的Delta值确定;假定上一个Option的标号为0,同一个编号的多个Option的实例,其Delta值为0。
- 取值0-12表示Option delta;取值为13,需要占用Option Delta extension中一个byte,存放实际option delta减13的值;取值为14,需要占用extension中两个字节,存放实际Option delta减去269的部分;取值为15,为payload marker保留。
- Option Length:取值0~12表示option占用的字节数;取值13表示需要占用扩展中的一个字节,且表示option length减13的部分;取值14表示需要占用扩展中的两个字节,且表示option length减去269部分;取值15表示保留;
- Option Value:Option的具体内容。
- 0长度的字符序列
- 不透明的字节序列
- 无符号整数
- UTF-8编码的Unicode字符串
- CoAP的Option的编号方式:
NO. | C | U | N | R | Name | Format | Length | Default |
---|---|---|---|---|---|---|---|---|
1 | x | x | If-Match | opaque | 0~8 | (none) | ||
3 | x | x | - | Uri-Host | string | 1~255 | (see below) | |
4 | x | ETag | opaque | 0~8 | (none) | |||
5 | x | If-None-Match | enpty | 0 | (none) | |||
7 | x | x | - | Uri-Port | uint | 0~2 | (see below) | |
8 | x | Location-Path | string | 0~255 | (none) | |||
11 | x | x | - | x | Uri-Path | string | 0~255 | (none) |
12 | Content-Format | uint | 0~2 | (none) | ||||
14 | x | - | Max-Age | uint | 0~4 | 60 | ||
15 | x | x | - | x | Uri-Query | string | 0~255 | (none) |
17 | x | Accept | uint | 0~2 | (none) | |||
20 | x | Location-Query | string | 0~255 | (none) | |||
35 | x | x | - | Proxy-Uri | string | 1~1034 | (none) | |
39 | x | x | - | Proxy-Scheme | string | 1~255 | (none) | |
60 | x | Sizel | uint | 0~4 | (none) |
- Option编号内容:
- Content-Format和Accept用于表示CoAP负载的媒体格式:
- Uri-Host、Uri-Port、Uri-Path和Uri-Query等和资源“位置”和参数有关:
- Content-Format:指定CoAP复杂媒体类型,媒体类型采用整数描述,例如application/json对应整数50,application/octet-stream对应整数40。
- Accept: 指定CoAP响应复杂中的媒体类型,媒体类型的定义和Content-Format相同
- Uri-Host:CoAP主机名称,例如:iot.xxxx.org。
- Uri-Host:CoAP端口号,默认5683。
- Uri-Path:资源路由或路径,例如temperature。资源路径采用UTF8字符串形式,长度不计第一个""。
- Uri-Query:访问资源参数,例如?value1=1&value2=2,参数与参数之间使用“&”分隔,Uri-Query和Uri-Path之间采用“?”分隔。
- Content-Format描述:
Media type | Encoding | ID | Reference |
---|---|---|---|
text/plain; | - | 0 | [RFC2026] [RFC3676] |
charset=utf-8 | [RFC5147] | ||
application/link-format | - | 40 | [RFC6690] |
application/xml | - | 41 | [RFC3023] |
application/octet-stream | - | 42 | [RFC2045] [RFC2046] |
application/exi | - | 47 | [RFC-exi-20140211] |
application/json | - | 50 | [RFC7159] |
- Content-Format编号内容:
- text/plain: 编号为0,表示负载为字符串形式,默认为UTF8编码。
- application/link-format:编号为40,CoAP资源发现协议中追加定义,该媒体类型为CoAP协议特有。
- application/xml:编号为41,表示负载类型为XML格式。
- application/octet-stream:编号为42,表示负载类型为 二进制格式。
- application/exi:编号为47,表示负载类型为“精简XML”格式。(翻译不一定准确)
- 另外,还有一种格式也IANA认定,也会在CoAP协议中广泛使用那便是CBOR格式,该格式可理解为 二进制JSON格式。
- applicaiton/cbor:编号为60。
CoAP实例:
- 实例说明:CoAP客户端通过GET方法从Server端获取温度数据。
- CoAP请求报文采用CON报文,Server接收到CON报文必须返回一个ACK报文。
- CoAP请求采用0.01 GET方法,若操作成功CoAP Server返回2.05 Content。
- 请求和响应的MID必须完全相同,此处为0x1234。
- 请求响应中的Token域为空。
- CoAP请求中包含Option,该Option的类型为Uri-Path,那么Option Delta的值为0 11=11。
- Option Value的值为字符串形式的“temp”。
- CoAP返回中包含温度数据。
- 实例模型
Client Server
| GET | Header:GET(T=CON, Code=0.01, MID=0x1234)
--------->| Uri-Path: "temp"
| 2.05 |
<---------| Header: 2.05 Content (T=ACK, Code=2.05, MID=0x1234)
| | Payload: "22.3 C"
- 报文格式
/* Client -> Server */
2 2 4 8 16
--- --- ------- ---------------- ---------------------------|
| 1 | 0 | 0 | GET=1 | MID=0x1234 |
------------------------------------------------------------|
| 11 | 4 | "temp"(4byte) |
--------------- --------------------------------------------|
/* Server -> Client */
2 2 4 8 16
--- --- ------- ---------------- ---------------------------|
| 1 | 2 | 0 | 2.05=59 | MID=0x1234 |
------------------------------------------------------------|
|1 1 1 1 1 1 1 1| "22.3 C"(6byte) |
--------------- --------------------------------------------|
总结
- 在物联网终端设备大多都是资源限制型的。有限的CPU、RAM、Flash、网络宽带等。
- 对于这类设备使用TCP或HTTP是不现实的。
- 基于这种考虑,CoAP协议就被设计出来,如应用在NB-IOT等等。
- 像水表那些,不用长连接的,使用这个协议,可以增加续航等能力。