COAP (Constrained Application Protocol)是一种在物联网世界的类 HTTP 的协议,使用在资源受限的物联网设备上,它的详细规范定义在 RFC 7252。
由于物联网设备大多都是资源限制型的,比如 CPU、RAM、Flash、网络宽带等。对于这类设备来说,想要直接使用现有网络的TCP和HTTP来实现设备实现信息交换是不现实的。为了让这部分设备能够顺利接入网络,CoAP 协议应运而生。
COAP运行于UDP之上,与MQTT一样都是比较成熟的物联网协议。
特性
- 在受限条件下满足M2M需求的Web协议环境
- 拥有可选的可靠性特性的UDP,支持单播与组播请求
- 异步信息交互
- 低报头开销与低解析复杂性
- 支持URI与Content-type
- 简单的代理与缓存功能
这篇文章只简单介绍CoAP的交互模型与数据结构
交互模型
+----------------------+
| Application |
+----------------------+
+----------------------+ \
| Requests/Responses | |
|----------------------| | CoAP
| Messages | |
+----------------------+ /
+----------------------+
| UDP |
+----------------------+
在UDP之上,一共有两种交互模型,一个是消息模型Messages,一个是请求响应模型Request/Response。首先我们需要知道消息有4种类型,分别是:
- Confirmable(CON),可确认消息
- Non-confirmable(NON),无需确认消息
- Acknowledgement(ACK),确认消息
- Reset(RST),重置消息
消息模型
消息的可靠性是通过可确认消息(CON)来提供的。可确认消息(CON)使用默认的超时机制进行传输与使用指数级退避机制进行重传,直到接收者回复携带了Message ID(在这例子中,就是0x7d34)的确认消息(ACK)。见下图,当接收者无法处理可确认消息(CON)时,回复重置消息(RST)。
Client Server
| |
| CON [0x7d34] |
+----------------->|
| |
| ACK [0x7d34] |
|<-----------------+
| |
如果消息不需要可靠性,可以发送无需确认消息(NON)。这情景下,没有确认消息(ACK),但还是拥有Message ID(在这例子中,就是0x01a0)来检测消息是否重复。见下图,当接收者无法处理无确认消息(NON)时,它应该回复重置消息(RST)。
Client Server
| |
| NON [0x01a0] |
+----------------->|
| |
请求与响应模型
请求携带于可确认消息(CON)或无需确认消息(NON),而且如果响应的足够的快,该请求的响应可以携带于确认消息(ACK)中。这种形式,称为piggybacked response(这里暂译为同步响应)(这里不需要单独的对同步响应进行ACK,因为当客户端没接收到同步响应时会重传请求)
Client Server Client Server
| | | |
| CON [0xbc90] | | CON [0xbc91] |
| GET /temperature | | GET /temperature |
| (Token 0x71) | | (Token 0x72) |
+----------------->| +----------------->|
| | | |
| ACK [0xbc90] | | ACK [0xbc91] |
| 2.05 Content | | 4.04 Not Found |
| (Token 0x71) | | (Token 0x72) |
| "22.5 C" | | "Not found" |
|<-----------------+ |<-----------------+
| | | |
而如果服务器不能马上对可确认消息(CON)中的请求进行响应,它可以简单回复ACK消息,以便客户端停止重传请求。当响应就绪时,服务器可以发送一个新的可确认消息(CON)(这时反过来需要客户端ACK确认)
Client Server
| |
| CON [0x7a10] |
| GET /temperature |
| (Token 0x73) |
+----------------->|
| |
| ACK [0x7a10] |
|<-----------------+
| |
... Time Passes ...
| |
| CON [0x23bb] |
| 2.05 Content |
| (Token 0x73) |
| "22.5 C" |
|<-----------------+
| |
| ACK [0x23bb] |
+----------------->|
| |
如果请求是无需确认消息(NON),则可以使用无需确认消息(NON)进行响应,尽管服务器可能使用可确认消息(CON)响应。
Client Server
| |
| NON [0x7a11] |
| GET /temperature |
| (Token 0x74) |
+----------------->|
| |
| NON [0x23bc] |
| 2.05 Content |
| (Token 0x74) |
| "22.5 C" |
|<-----------------+
| |
数据结构
CoAP由四大部分组成:分别是Header、Token、Options与Payload。
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Ver| T | TKL | Code | Message ID |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Token (if any, TKL bytes) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Options (if any) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|1 1 1 1 1 1 1 1| Payload (if any) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Header
固定4个字节,分别由Ver、T、TKL、Code与MessageID组成。
Ver
2位无符号整数。表示CoAP的版本号。该规范的实现必须设置该字段为1(即0b01)。其他值保留给未来的版本使用。版本号未知的消息必须被静默地忽略。
T
2位无符号整数。表示该消息是否为类型:
- Confirmable(0)
- Non-confirmable(1)
- Acknowledgement(2)
- Reset(3)
Token
4位无符号整数。表示可变长Token的长度,能表示0-8字节(4位,能表示0~15)。长度9-15为保留,不能发送,收到则作为格式错误处理。
Code
8位无符号整数。前3位表示class,后5位表示detail。记录为"c.dd ",其中"c"指从0到7的数字即前3位,“dd”是两位数字,00 ~ 31即后5位。
class的值如下:
- a request(0)
- a success response(2)
- a client error response(4)
- a server error response(5)
- 其它值保留
具体的范围如下:
-
0.00 表示是一个空消息
-
0.01-0.31 表示一个请求
+------+--------+-----------+ | Code | Name | Reference | +------+--------+-----------+ | 0.01 | GET | [RFC7252] | | 0.02 | POST | [RFC7252] | | 0.03 | PUT | [RFC7252] | | 0.04 | DELETE | [RFC7252] | +------+--------+-----------+ -
1.00-1.31 保留
-
2.00-5.31 表示一个响应
+------+------------------------------+-----------+ | Code | Description | Reference | +------+------------------------------+-----------+ | 2.01 | Created | [RFC7252] | | 2.02 | Deleted | [RFC7252] | | 2.03 | Valid | [RFC7252] | | 2.04 | Changed | [RFC7252] | | 2.05 | Content | [RFC7252] | | 4.00 | Bad Request | [RFC7252] | | 4.01 | Unauthorized | [RFC7252] | | 4.02 | Bad Option | [RFC7252] | | 4.03 | Forbidden | [RFC7252] | | 4.04 | Not Found | [RFC7252] | | 4.05 | Method Not Allowed | [RFC7252] | | 4.06 | Not Acceptable | [RFC7252] | | 4.12 | Precondition Failed | [RFC7252] | | 4.13 | Request Entity Too Large | [RFC7252] | | 4.15 | Unsupported Content-Format | [RFC7252] | | 5.00 | Internal Server Error | [RFC7252] | | 5.01 | Not Implemented | [RFC7252] | | 5.02 | Bad Gateway | [RFC7252] | | 5.03 | Service Unavailable | [RFC7252] | | 5.04 | Gateway Timeout | [RFC7252] | | 5.05 | Proxying Not Supported | [RFC7252] | +------+------------------------------+-----------+ -
6.00-7.31 保留
Message ID
16位无符号整数。用于检测消息重复和对Acknowledgement/Rest信息和Confirmable/Non-confirmable进行匹配。能表示65535个数。
Token
用于关联请求与响应。由Header的TKL决定长度,长度为0-8字节。
Options
由0个或多个Option组成。
0 1 2 3 4 5 6 7
+---------------+---------------+
| | |
| Option Delta | Option Length | 1 byte
| | |
+---------------+---------------+
\ \
/ Option Delta / 0-2 bytes
\ (extended) \
+-------------------------------+
\ \
/ Option Length / 0-2 bytes
\ (extended) \
+-------------------------------+
\ \
/ /
\ \
/ Option Value / 0 or more bytes
\ \
/ /
\ \
+-------------------------------+
Option Delta:4位无符号整型。0-12用于表示Option Delta。3个特殊值:
- 13: 在初始字节后的8位无符号整型,减去13表示Option Delta。
- 14: 在初始字节后的16位无符号整型,减去269表示Option Delta。
- 15:保留给Payload标记
目前Option Delta对应的字段:
+--------+------------------+-----------+
| Number | Name | Reference |
+--------+------------------+-----------+
| 0 | (Reserved) | [RFC7252] |
| 1 | If-Match | [RFC7252] |
| 3 | Uri-Host | [RFC7252] |
| 4 | ETag | [RFC7252] |
| 5 | If-None-Match | [RFC7252] |
| 7 | Uri-Port | [RFC7252] |
| 8 | Location-Path | [RFC7252] |
| 11 | Uri-Path | [RFC7252] |
| 12 | Content-Format | [RFC7252] |
| 14 | Max-Age | [RFC7252] |
| 15 | Uri-Query | [RFC7252] |
| 17 | Accept | [RFC7252] |
| 20 | Location-Query | [RFC7252] |
| 35 | Proxy-Uri | [RFC7252] |
| 39 | Proxy-Scheme | [RFC7252] |
| 60 | Size1 | [RFC7252] |
| 128 | (Reserved) | [RFC7252] |
| 132 | (Reserved) | [RFC7252] |
| 136 | (Reserved) | [RFC7252] |
| 140 | (Reserved) | [RFC7252] |
+--------+------------------+-----------+
Option Length:4位无符号整型。0-12用于表示Option Length。3个特殊值:
- 13: 在初始字节后的8位无符号整型,减去13表示Option Length。
- 14: 在初始字节后的16位无符号整型,减去269表示Option Length。
- 15:保留给未来扩展使用
Option Value:文档中定义的选项使用了以下选项值的格式:
- empty:长度为0的字节序列
- opaque:不透明的字节序列
- uint:无符号整型
- string:UTF-8编码的字节串
Payload
如果存在且长度不为0,则前面固定1个标记(0xFF),用来表示Options块结束和Payload块开始。