跳到主要内容

1. 引言 (Introduction)

1.1. 背景 (Background)

受限应用协议 (Constrained Application Protocol, CoAP) [RFC7252] 旨在提供类似 HTTP [RFC7230] 的 RESTful 服务 [REST], 同时降低实现复杂度以及交换数据包的大小, 使这些服务可用于由高度受限节点 [RFC7228] 组成的高度受限网络.

REST 的模型是客户端与服务器交换资源的表示, 其中表示捕获资源当前的状态或预期的状态. 服务器是其命名空间中资源表示的权威来源. 对资源状态感兴趣的客户端向服务器发起请求, 服务器随后返回一个响应, 其中包含该请求发生时资源的当前表示.

当客户端希望在一段时间内持续拥有资源的当前表示时, 该模型并不适用. HTTP 中已有的方法, 例如重复轮询或 HTTP 长轮询 [RFC6202], 会产生显著的复杂度和/或开销, 因此不太适合受限环境.

本文档指定的协议使用一种机制扩展 CoAP 核心协议, 使 CoAP 客户端能够在 CoAP 服务器上 "观察" 一个资源: 客户端获取该资源的一个表示, 并请求服务器只要客户端仍对该资源感兴趣, 就持续更新此表示.

该协议保留 REST 的架构属性. 通过支持缓存和代理, 它实现了较高的可扩展性和效率. 不过, 本协议并不试图解决现有 HTTP 方案解决的全部问题, 也不试图取代用于解决更通用问题的发布/订阅网络 [RFC5989].

1.2. 协议概述 (Protocol Overview)

该协议基于众所周知的观察者设计模式 (observer design pattern) [GOF]. 在这种设计模式中, 称为 "观察者" 的组件向一个特定且已知的提供方注册, 该提供方称为 "主体"; 当主体发生状态变化时, 观察者希望收到通知. 主体负责管理其已注册观察者的列表. 如果观察者对多个主体感兴趣, 它必须分别向每个主体注册.

                       Observer             Subject
| |
| Registration |
+------------------->|
| |
| Notification |
|<-------------------+
| |
| Notification |
|<-------------------+
| |
| Notification |
|<-------------------+
| |

Figure 1: The Observer Design Pattern

观察者设计模式在 CoAP 中实现如下:

主体 (Subject): 在 CoAP 上下文中, 主体是 CoAP 服务器命名空间中的一个资源. 该资源的状态可能随时间变化, 变化频率可以从偶发更新到连续状态转换不等.

观察者 (Observer): 观察者是一个 CoAP 客户端, 它希望在任意给定时间都拥有该资源的当前表示.

注册 (Registration): 客户端通过向服务器发起扩展 GET 请求来注册其对资源的兴趣. 除了返回目标资源的表示之外, 该请求还会使服务器将客户端加入该资源的观察者列表.

通知 (Notification): 每当资源状态发生变化时, 服务器都会通知该资源观察者列表中的每个客户端. 每个通知都是服务器针对这一单个扩展 GET 请求发送的额外 CoAP 响应, 并包含新的资源状态的完整且已更新的表示.

下面的 Figure 2 展示了一个 CoAP 客户端注册对某个资源的兴趣并接收三个通知的示例: 第一个通知携带注册时的当前状态, 后两个通知则在资源状态变化时发送. 注册请求和通知都通过本文档定义的 Observe Option 来标识. 在通知中, Observe Option 还提供用于重排序检测的序列号. 所有通知都携带客户端指定的令牌, 因此客户端可以轻松地将它们与请求关联起来.

                       Client                Server
| |
| GET /temperature |
| Token: 0x4a | Registration
| Observe: 0 |
+------------------->|
| |
| 2.05 Content |
| Token: 0x4a | Notification of
| Observe: 12 | the current state
| Payload: 22.9 Cel |
|<-------------------+
| |
| 2.05 Content |
| Token: 0x4a | Notification upon
| Observe: 44 | a state change
| Payload: 22.8 Cel |
|<-------------------+
| |
| 2.05 Content |
| Token: 0x4a | Notification upon
| Observe: 60 | a state change
| Payload: 23.1 Cel |
|<-------------------+
| |

Figure 2: Observing a Resource in CoAP

注: 在本文档中, "Cel" 表示 "摄氏度".

只要服务器能够确定客户端仍持续关注该资源, 客户端就会留在观察者列表中. 服务器可以在可确认 CoAP 消息中发送通知, 以请求客户端确认. 当客户端注销, 拒绝某个通知, 或通知传输在多次尝试后超时时, 客户端被视为不再对该资源感兴趣, 并由服务器从观察者列表中移除.

1.3. 一致性模型 (Consistency Model)

当客户端位于某个资源的观察者列表中时, 该协议的目标是让客户端观察到的资源状态尽可能接近服务器上的实际状态.

客户端和服务器有时不可避免会失去同步: 第一, 资源状态发生变化与通知被接收之间总是存在一定延迟. 第二, 携带通知的 CoAP 消息可能丢失, 这会导致客户端在收到新通知之前一直假定资源处于旧状态. 第三, 服务器可能错误地认定客户端不再对该资源感兴趣, 从而停止发送通知, 客户端也会因此一直假定资源处于旧状态, 直到它最终再次注册兴趣.

该协议按如下方式处理此问题:

  • 它采用尽力而为的方法, 在状态变化后将当前表示发送给客户端: 客户端应当尽快看到状态变化后的新状态, 并且应当看到尽可能多的状态. 不过, 这受到拥塞控制的限制, 因此客户端不能依赖于观察资源可能经历的每一个状态.

  • 它为通知标记一个最大持续时间, 在此时间内允许观察到的状态与实际状态不同步. 当收到的通知的年龄达到此限制时, 客户端在收到新通知之前不能使用其中包含的表示.

  • 它基于最终一致性原则设计: 该协议保证, 如果资源没有再次发生状态变化, 最终所有已注册观察者都会拥有最新资源状态的当前表示.

1.4. 可观察资源 (Observable Resources)

CoAP 服务器负责判定资源在什么条件下改变其状态, 以及观察者何时会收到新资源状态的通知. 该协议不提供设置触发器或阈值的显式方式; 服务器需要暴露在应用上下文中以有用方式改变状态的可观察资源.

例如, 带有温度传感器的 CoAP 服务器可以暴露以下一个或多个资源:

  • <coap://server/temperature>, 其状态每隔几秒改变为温度传感器的当前读数;

  • <coap://server/temperature/felt>, 当温度读数低于某个预配置阈值时, 其状态变为 "COLD"; 当读数超过第二个略高的阈值时, 其状态变为 "WARM";

  • <coap://server/temperature/critical?above=42>, 其状态基于客户端指定的参数值而变化: 如果温度超过阈值, 则每隔几秒变为当前温度读数; 如果读数降到阈值以下, 则变为 "OK";

  • <coap://server/?query=select+avg(temperature)+from+Sensor.window:time(30sec)>, 它接受任意复杂度的表达式, 并相应地改变其状态.

因此, 通过设计在特定条件下改变状态的 CoAP 资源, 可以只在这些条件发生时更新客户端, 而不必持续向其提供原始传感器数据. 通过对资源进行参数化, 这种方式不限于服务器定义的条件, 还可以扩展到客户端指定的任意复杂查询. 因此, 应用设计者可以为预期应用和相关设备选择恰当的复杂度级别, 而不会受限于内置在协议中的 "一刀切" 机制.

1.5. 需求表示法 (Requirements Notation)

本文档中的关键词 "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", 和 "OPTIONAL" 应按 RFC 2119 [RFC2119] 中的说明解释.