coap协议
一、coap协议基础
1.1 什么是CoAp
CoAP是受限制的应用协议(Constrained Application Protocol)的代名词。但是对于小型设备而言,实现TCP和HTTP协议显然是一个过分的要求。为了让小设备可以接入互联网,CoAP协议被设计出来。 CoAP是一种应用层协议,它运行于 UDP协议之上而不是像HTTP那样运行于TCP之上。CoAP协议非常小巧,最小的数据包仅为4字节。CoAp是一个完整的二进制应用层协议,借鉴了HTTP协议的设计并简化了协议包格式,降低了开发者的学习成本。
1.2 CoAp消息结构

Version:版本号
T:message type—消息类型
- CON—需要被确认的请求,如果CON请求被发送,那么对方必须做出响应。
- NON—不需要被确认的请求,如果NON请求被发送,那么对方不必做出回应。
- ACK—应答消息,接受到CON消息的响应。
- RST—复位消息,当接收者接受到的消息包含一个错误,接受者解析消息或者不再关心发送者发送的内容,那么复位消息将会被发送。
TKL:CoAP标识符长度。CoAP协议中具有两种功能相似的标识符,一种为Message ID(报文编号),一种为Token(标识符)。其中每个报文均包含消息编号,但是标识符对于报文来说是非必须的。
Code:功能码/响应码。Code在CoAP请求报文和响应报文中具有不同的表现形式,Code占一个字节,它被分成了两部分,前3位一部分,后5位一部分,为了方便描述它被写成了c.dd结构。其中0.XX表示CoAP请求的某种方法,而2.XX、4.XX或5.XX则表示CoAP响应的某种具体表现。
Message ID:报文编号
Token:标识符具体内容,通过TKL指定Token长度。
options:CoAP选项类似于HTTP请求头,它包括CoAP消息本身,例如CoAP端口号,CoAP主机和CoAP查询字符串等。
1111 1111:CoAP报文和具体负载之间的分隔符。
playload:真正有用的被交互的数据。
除了Ver、T、TKE、Code、Message ID之外其他的都是可选的,这也是为什么最小的数据包仅4个字节的原因。
1.3 CoAP协议特点
- 满足受限环境下M2M的需求的协议
- CoAP协议基于UDP
- 异步消息交换
- 轻量级的头部,且解析复杂度低。
- 支持URI和Content-Type
- 能实现简单的缓存和数据代理
- 无状态的HTTP映射,可以构建代理服务器,使CoAP资源可以用HTTP协议访问,也可以使HTTP接口实现于CoAP协议之上
- 支持DTLS
二、Message Format
Message组成部分:
- 固定的4个字节的头部
- 0-8字节的Token
- 0或者多个TLV(Type-Length-Value)格式的Option
- 可选的Payload
三、code
Code部分被分成了两部分,为了便于阅读,Code被描述为c.dd形式。具体内容可参考RFC7252 #12.1.1 Method Codes。
3.1 请求
在CoAP请求中,Code被定义为CoAP请求方法,这些方法有GET、POST、PUT和DELETE,这些方法和HTTP协议非常相似。
【0.01】GET方法——用于获得某资源
【0.02】POST方法——用于创建某资源
【0.03】PUT方法——用于更新某资源
【0.04】DELETE方法——用于删除某资源
(1)GET: GET方法检索信息的表示形式,当前对应于请求URI标识的资源。如果请求中包含接受选项,则表明响应的首选内容格式。如果请求中包含ETag选项,GET方法要求验证ETag以及仅当验证失败时,才转移表示。若成功,应使用2.05(内容)或2.03(有效)响应代码出现在回应中。GET方法安全且幂等。
(2)POST: POST方法要求封装在要求得到处理。POST执行的实际功能方法由源服务器确定,并取决于目标资源。通常会导致创建新资源或目标资源正在更新。如果已在服务器上创建资源,则返回响应服务器应具有2.01(已创建)响应代码,应以一个或多个顺序包含新资源的URI位置路径和/或位置查询选项(第5.10.7节)。如果POST成功,但不会导致在上创建新资源在服务器上,响应应具有2.04(已更改)响应代码。如果POST成功并导致目标资源被占用删除后,响应应具有2.02(已删除)响应代码。POST既不安全也不幂等 。
(3)PUT: PUT方法请求由请求标识的资源使用随附的表示法更新或创建URI。表示的格式由媒体类型和内容指定Content-Format选项中提供的编码(如果提供)。如果请求URI处存在资源,则随附的表示形式应该被认为是该资源的修改版,并且是2.04(已更改)应返回响应代码。如果没有资源,然后服务器可以使用该URI创建一个新资源,结果是2.01(创建的)响应代码。如果无法创建资源或修改后,应发送适当的错误响应代码。通过包含If-Match可以对PUT进行进一步的限制或“如果不匹配”请求中的选项。PUT是不安全的,但是幂等的。
(4)DELETE: DELETE方法请求由请求URI被删除。2.02(已删除)响应代码应为成功使用时或如果资源不存在之前使用请求。DELETE是不安全的,但是是幂等的
3.2 响应
响应代码分为3类:
2-成功:成功接收,理解并请求公认。
4-客户端错误:请求包含错误的语法或无法实现。
5-服务器错误:服务器未能履行表面上有效的命令请求
在CoAP响应中,Code被定义为CoAP响应码,类似于HTTP 200 OK等等。
【2.01】Created.回复POST或者PUT。
【2.02】Deleted.回复DELETE,有些情况下的POST。
【2.03】Valid.Indicate that the response identified by the entity-tag identified by the included ETag Option is valid.则,Response必须带ETag Option。
【2.04】Changed.回复POST和PUT。
【2.05】Content.类似于HTTP 200 OK–服务器成功处理了请求回复GET。【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.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 服务器不支持代理功能。
四、Token
4.1 Token生成方法
令牌用于将响应与请求匹配。令牌Value为0 ~ 8字节的序列。(注意每条消息携带一个令牌,即使它的长度为零。)每个请求带有客户端生成的令牌,服务器必须回显(不包含)修改)。令牌旨在用作客户端本地标识符区分并发请求;它可以称为“请求ID”。
方法一:MD5加盐法(HASH+SALT),实现一人一密。
所谓加盐(SALT)其实就是生成HASH时给予一个干扰,使结果与标准的HASH结果不同,从而对抗彩虹表。比如说用户密码‘88888888’,加一个盐(一个随机字符串)‘q1we2rt3y6u8io7p’,拼接到一起在计算MD5,结果值就变了。这样即使用户使用弱密码,也能一定程度上防御彩虹攻击。但是如果每个密码加的盐都是一样的,那么就又回到了之前的问题了。
一人一密
我们要实现,相同的站点,不同用户的相同的密码口令不同。这样就能有效的对付碰撞和统计攻击。例如:加自定义的盐。密码拼接用户名或者时间戳在计算MD5。
方法二:
(1) 用户请求时携带此token(分为三部分,header密文, payload密文,签名)到服务端,服务端解析第一部分(header密文),用base64解密,可以知道用了什么算法。
(2)服务端使用原来的秘钥与密文(header密文+“.”+payload密文)同样进行HS256运算,然后用生成的签名与token携带的签名进行比对,若一致说明token合法,不一致说明原文被修改
(3)判断是否过期,客户端通过用base64解密第二部分(payload密文),可以知道荷载中授权时间,以及有效期.通过这个与当前时间对比发现token是否过期。
4.2 报文分析
五、option
请求和响应都可能包含一个或多个选项的列表。例如,请求中的URI是在几个选项中传输的,而将在HTTP中的HTTP头中携带的元数据也作为选项提供。
5.1 Critical/Elective
选项分为两类:“Critical”和“Elective”。它们之间的区别在于端点无法识别的选项是如何处理的:
- Critical Option:接收方必须可以理解的 Option,不然消息没法正常处理
- Elective Option:接收方不识别该 Option 时,能够忽略,不影响消息的正常处理
5.2 Proxy Unsafe or Safe-to-Forward and NoCacheKey
根据Proxy对于未被识别的Option的处理分为Unsafe or Safe-to-Forward Option。
除了将一个选项标记为Critical/Elective外,还根据代理在不识别该选项时如何处理该选项进行分类。为此目的,一个选项可以被认为是不安全的转发(不安全设置)或安全的转发(不安全设置)。此外,对于标记为Safe-to-Forward的选项,该选项编号指示它是否打算成为请求中Cache-Key的一部分。如果某些NoCacheKey位是0,则为0;如果所有的NoCacheKey都是1,则它不是。
注意:Cache-Key指示仅适用于那些不将给定选项作为请求选项实现,而只依赖于Unsafe/Safe-to-Forward指示的代理。例如,对于ETag,实际上使用请求选项作为Cache-Key的一部分是非常低效的,但如果ETag不是通过代理实现的,这是最好的方法,因为响应将根据请求选项的存在而不同。实现ETag请求选项的一个更有用的代理是不使用ETag作为Cache-Key的一部分。NoCacheKey以3位表示,因此8个码点中只有1个是合格的NoCacheKey,而8个码点中有7个似乎是更可能的情况。
注意:
- 对于不能识别的非重要选项,无声的忽略该选项。
- 在Con Request中的不能识别的重要选项,需要返回4.02(请求中包含错误选项),且携带该选项用于诊断。
- 在Con Response中或者附带响应数据中不能识别的重要选项,必须拒绝接受这个Response。
- 在Non(不需应答消息)中不能识别的选项,必须拒绝接受这个消息(返回reset并忽略non)。
- Rejecting a Confirmable message is effected by sending a matching,Reset message and otherwise ignoring it.(拒绝可确认消息是通过发送匹配来实现的,重置消息而忽略它。)
5.3 Length
选项值被定义为具有特定的长度,通常是上界和下界的形式。如果请求中的选项值的长度超出了定义的范围,则必须将该选项视为未识别的选项。
5.4 Option Number
选项由选项号标识,选项号还提供了一些额外的语义信息,例如,奇数表示关键选项,而偶数表示可选选项。注意,这不仅仅是一种约定,它是协议的一个特征:一个选项是Critical/Elective,取决于它的Option Number是偶数还是奇数。并且,选项号是用位掩码构造的,用来指示一个选项是“Critical”还是“Elective”、“Unsafe”还是“ Safe-to-Forward”,并且,在 Safe-to-Forward的情况下,提供一个Cache-Key指示如下图所示。在下面的文本中,位掩码表示为一个单字节,该单字节应用于无符号整数表示的选项数的最低有效字节。当第7位(最低有效位)为1时,一个选项是Critical(当0时同样是optional)。当第6位为1时,一个选项是Unsafe(同样,当0时是安全转发的)。当第6位为0时,即,该选项不是不安全的,当且仅当第3-5位全部设置为1时,它不是一个Cache-Key (NoCacheKey);所有其他的位组合意味着它确实是一个Cache-Key。
不同的Option有不同Option Number来表示。
Critical = (onum & 1);
UnSafe = (onum & 2);
NoCacheKey = ((onum & 0x1e) == 0x1c);
5.5 Option Format
一般情况下Option部分包含Option Delta、Option Length和Option Value三部分。
【Option Delta】表示Option的增量,当前的Option的具体编号等于之前所有Option Delta的总和。
【Option Length】表示Option Value的具体长度。
【Option Value】表示Option具体内容

选项中的字段定义如下:
选项Delta:4位无符号整数。介于0和12之间的值表示期权增量。保留三个值以用于特殊结构体:
13:8位无符号整数紧跟在初始字节之后,表示期权差值减去13。
14:跟随网络字节顺序的16位无符号整数初始字节,表示Option Delta减去269。
15:为有效负载标记保留。如果该字段设置为此值,但整个字节不是有效载荷标记,这必须被处理为消息格式错误。
选项长度:4位无符号整数。介于0和12之间的值,指示选项值的长度,以字节为单位。三个价值观保留用于特殊构造:
13:选项值前面有一个8位无符号整数,并且表示期权长度减去13。
14:以网络字节顺序排列的16位无符号整数位于选项值,指示选项长度减去269。
15:保留供将来使用。如果该字段设置为此值,必须将其作为消息格式错误进行处理。
值:正好是“选项长度”字节的序列。长度和选项值的格式取决于相应的选项,即可以定义可变长度值。
5.6 Option Definitions
下表总结了各个CoAP选项,并在本节的小节中进行了解释。在该表中,C、U和N列分别表示属性Critical、UnSafe和NoCacheKey。由于NoCacheKey只对安全转发(没有标记为不安全)的选项有意义,因此列中填充了一个短横线表示不安全选项。
5.6.1 Uri-Host, Uri-Port, Uri-Path, and Uri-Query
在这些option中,Uri-Host、Uri-Port、Uri-Path和Uri-Query等和资源“位置”和参数有关。
【3】Uri-Host:CoAP主机名称,例如iot.eclipse.org
【7】Uri-Port:CoAP端口号,默认为5683
【11】Uri-Path:资源路由或路径,例如\temperature。资源路径采用UTF8字符串形式,长度不计第一个""。
【15】Uri-Query:访问资源参数,例如?value1=1&value2=2,参数与参数之间使用“&”分隔,Uri-Query和Uri-Path之间采用“?”分隔。
5.6.2 Content-Format
Content-Format选项指示消息有效负载的表示格式。表示格式是作为一个数字内容格式标识符给出的,该标识符在“CoAP ContentFormats”注册表中定义。如果没有该选项,则不会假定任何默认值,即任何表示消息有效负载的表示格式都是不确定的。Internet媒体类型由字符串标识,例如“application/xml”。
5.6.3 Accept
CoAP Accept选项可用于指示客户端可接受的内容格式。表示格式由数字内容格式标识符给出,该标识符在“CoAP内容格式”注册表(章节12.3)中定义。如果没有给出Accept选项,则客户端不会表示首选项(因此不会假定默认值)。客户端希望服务器返回的表示是指定的Content-Format。如果可用,服务器将返回首选的Content-Format。如果首选的ContentFormat不能返回,则必须发送4.06“不可接受”作为响应,除非另一个错误代码优先此响应。
5.6.4 ETag
ETag:是实体标签(Entity Tag)的缩写。ETag一般不以明文形式响应给客户端。在资源的各个生命周期中,它都具有不同的值,用于标识出资源的状态。当资源发生变更时,如果其头信息中一个或者多个发生变化,或者消息实体发生变化那么ETag也随之发生变化。ETag值的变更说明资源状态已经被修改。往往可以通过时间戳就可以得到ETag头信息。服务器计算ETag值,并在相应客户端请求时将它返回给客户端。
(1)ETag作为响应选项
响应中的ETag选项提供实体标签的当前值(即,在请求被处理后),用于“标记表示”。如果没有Location-选项,则标记表示是目标资源的选定表示。如果存在一个或多个Location-选项,并因此指示了一个位置URI,则标记的表示形式将被位置URI的GET请求检索到。
ETag响应选项可以包含在任何有标记表示的响应中(例如,它在4.04或4.00响应中没有意义)。ETag选项在响应中不能出现超过一次。
ETag选项没有默认值;如果它不在响应中,服务器就不会对标记表示的实体标记做出任何声明。
(2)ETag作为请求选项
在GET请求中,端点可以为一个或多个存储响应指定一个ETag Option实例,该端点以前从资源中获得一个或多个表示,并且已经通过这些表示获得了ETag响应选项。如果给定的一个ETags是当前表示的,即有效的,服务器可以发出一个2.03有效响应来代替2.05内容响应;然后在响应选项中返回这个特定的ETag。实际上,客户端可以确定存储的表示是否为当前的,而不需要再次传输它们。
六、TLV header
所谓通讯协议就是指通信双方对数据传送控制的一种约定。约定中包括对数据格式,同步方式,传送速度,传送步骤,纠错方式以及控制字符定义等问题做出统一规定,通信双方必须共同遵守,倘若一方不遵守,便会直接导致数据不能被解析!更通俗来讲,它可以理解两个节点之间为了协同工作实现信息交换,协商一定的规则和约定,例如规定字节序,各个字段类型等。

- Tag:标记;
- Length:一般为value的长度,也可以是整个TLV的长度;
- Value:真正的数据长度。
七、传输特性
7.1 Message的可靠传输
Client构造Con Msg 发送到Server,未收到ACK或Reset时,支持基于指数回退的重发;
注:客户端发送消息到服务端,需要等待服务器收到通知, 如果在规定时间内没有收到确认消息(ACK)或者复位消息(RST),需要重新发送数据。
Server如果可以处理该Message,返回ACK,否则返回Reset。可靠传输是基于CON消息传输的,服务器端收到CON类型的消息后,如果服务器可以处理这个消息,需要返回ACK消息,客户端到在指定时间ACK_TIMEOUT内收到ACK消息后,才代表这个消息已可靠到服务器端,不能处理的话就Rejecting一个消息,一般是返回Reset或者忽略它。
消息可靠传输相关参数:
名称 | 默认值 |
---|---|
ACK_TIMEOUT | 2 second |
ACK_RANDOM_FACTOR | 1.5 |
MAX_RETRANSMIT | 4 |
NSTART | 1 |
DEFAULT_LEISURE | 5s |
PROBING_RATE | 1 byte/second |
- ACK_TIMEOUT*ACK_RANDOM_FACTOR:初始的ACK保护时间(重传保护时间),随后的MAX_RETRANSMIT次重传都乘以2
- NSTART:最大并发的处于活动状态的Message数目
- DEFAULT_LEISURE:Server休闲时间,用于收到多播Request时,何时返回Response的随机时间的计算(上限)
- PROBING_RATE:经过MAX_RETRANSMIT次的Request最终未收到Response后,Requester发送对端的平均速率小于该值
7.2 Request/Respones模型
CoAP Request和Response的语法通过Message承载
可靠传输Request的响应方式有两种:
同步可靠响应模式: 通过Con msg的ACK携带Response
异步可靠响应模式:当Server不能立即响应Request时,可以先通过空Ack msg响应Client,当Server准备好后,通过新的CON Msg将resonse发送给Client
非可靠传输Request和Response
7.2.1 同步可靠响应模式(piggybacked Response)
7.2.2 异步可靠响应模式(separate Response)
7.3 非可靠响应模式
备好后,通过新的CON Msg将resonse发送给Client
非可靠传输Request和Response