news 2026/6/9 14:20:24

网络技术21-CoAP协议详解——受限设备的“RESTful替代方案“

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
网络技术21-CoAP协议详解——受限设备的“RESTful替代方案“

「知识图谱生成工具」:一键将文件夹内容变身为交互式知识图谱的免安装桌面工具(文末附免费下载链接)-CSDN博客

AI工程师面试高频考点问题汇总下载链接

网络协议系列 · 第21篇 | 预计阅读时间:15分钟

💡 一句话理解CoAP

CoAP就像给HTTP减肥——HTTP是西装革履的大人,CoAP是穿T恤短裤的小孩,干的事差不多,但轻便多了。DTLS?那就是给小孩配的保镖。

一、为什么需要CoAP?

想象一下这个场景:你有一个纽扣电池供电的温度传感器,需要把数据上传到云端。如果用HTTP:

  • 一个HTTP请求头动辄几百字节,而传感器数据可能只有几个字节
  • TCP三次握手+TLS握手,电量还没传数据就耗光了
  • 设备内存只有几十KB,HTTP库都塞不进去

这就好比让一只蚂蚁去搬大象——不是蚂蚁不努力,是任务本身就不匹配。

CoAP的设计目标(RFC 7252):

  • 📡低功耗:适合电池供电设备,一次通信几毫焦耳
  • 📶低带宽:报文最小仅4字节,比HTTP头部还小
  • 🔧受限设备:几十KB内存就能跑
  • 🌐RESTful:保持HTTP的URI、方法、响应码等概念
  • 🔒安全:基于DTLS,轻量级加密

二、CoAP报文结构解剖

CoAP报文设计得极其紧凑,核心头部只有4个字节。让我们一层层剥开这个洋葱:

2.1 固定头部(4字节)

``` 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) ... +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ```
| 字段 | 位数 | 说明 | |---|---|---| | Ver (Version) | 2 bits | 协议版本,当前固定为1 | | T (Type) | 2 bits | 消息类型:CON(0), NON(1), ACK(2), RST(3) | | TKL (Token Length) | 4 bits | Token长度,0-8字节 | | Code | 8 bits | 请求方法或响应码 | | Message ID | 16 bits | 消息标识,用于去重和匹配 |

2.2 Code字段详解

Code字段是CoAP的"灵魂",它同时承担了HTTP中"方法"和"状态码"的职责:

Code = c.dd (8 bits) ↑ ↑ │ └── 4位小数部分 └──── 3位类别部分

类别含义: 0.xx = 请求方法 (GET/POST/PUT/DELETE) 2.xx = 成功响应 4.xx = 客户端错误 5.xx = 服务器错误

常用Code对照表: ┌─────────┬─────────────┬─────────────────┐ │ Code │ 名称 │ 对应HTTP │ ├─────────┼─────────────┼─────────────────┤ │ 0.01 │ GET │ GET │ │ 0.02 │ POST │ POST │ │ 0.03 │ PUT │ PUT │ │ 0.04 │ DELETE │ DELETE │ │ 2.01 │ Created │ 201 │ │ 2.02 │ Deleted │ 200/204 │ │ 2.04 │ Changed │ 200/204 │ │ 2.05 │ Content │ 200 │ │ 4.00 │Bad Request │ 400 │ │ 4.04 │Not Found │ 404 │ │ 5.00 │Internal Err │ 500 │ └─────────┴─────────────┴─────────────────┘

2.3 选项(Options)

CoAP用Options替代了HTTP的头部,采用TLV(Type-Length-Value)编码,支持高效压缩:

| Option | 编号 | 作用 | HTTP对应 | |---|---|---|---| | Uri-Host | 3 | 目标主机 | Host头 | | Uri-Path | 11 | 资源路径 | URL路径 | | Uri-Query | 15 | 查询参数 | Query String | | Content-Format | 12 | 内容格式 | Content-Type | | Max-Age | 14 | 缓存时间 | Cache-Control | | Observe | 6 | 观察模式 | WebSocket/长轮询 |

**💡 小知识:**CoAP选项采用"差分编码",后续选项只需要编码与前一选项的编号差值,进一步压缩报文大小。

三、请求/响应模型:四种消息类型

CoAP定义了四种消息类型,对应不同的可靠性需求:

┌─────────────────────────────────────┐ │ CoAP 消息类型 │ └─────────────────────────────────────┘ │ ┌─────────────────────────┼─────────────────────────┐ │ │ │ ▼ ▼ ▼ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ CON │ │ NON │ │ ACK │ │ (Confirmable)│ │(Non-Confirmable)│ │(Acknowledgement)│ │ 可靠传输 │ │ 不可靠传输 │ │ 确认消息 │ └─────────────┘ └─────────────┘ └─────────────┘ │ │ │ │ 需要确认 │ 无需确认 │ 对CON的回应 │ 类似TCP │ 类似UDP │ │ 重传机制 │ 即发即忘 │ │ │ │ ▼ ▼ ▼ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ RST │ │ (Reset) │ 典型场景: │ 重置消息 │ - 传感器周期性上报(NON) └─────────────┘ - 关键命令下发(CON) │ - 心跳检测(CON) │ - 实时通知(NON) │ └── 拒绝处理或会话重置

3.1 CON(Confirmable)- 可靠传输

CON消息需要接收方返回ACK确认,类似于TCP的可靠传输:

Client Server │ │ │ CON [0x7d34] GET /temperature │ │ ───────────────────────────────────────> │ │ │ │ ACK [0x7d34] 2.05 Content │ │ "22.5°C" │ │ │ │ │ │ [无ACK返回,即发即忘] │ │ │ │ 适用场景: │ │ - 周期性传感器数据上报 │ │ - 高频监控数据 │ │ - 实时性优先于可靠性 │

3.3 分离模式(Separate Response)

当服务器需要较长时间处理请求时,可以先回ACK,再单独发响应:

Client Server │ │ │ CON [0x1234] GET /complex-query │ │ ───────────────────────────────────────> │ │ │ │ ACK [0x1234] [Empty] │ │ │ 客户端确认

四、观察者模式(Observe)

这是CoAP最酷的特性之一!它让服务器能主动推送资源变化给客户端,而不需要客户端轮询。

🎯 类比理解

传统HTTP轮询就像你每隔5分钟给餐厅打电话问"我的外卖好了吗"。 CoAP Observe就像你下单时跟餐厅说"做好了直接打我电话",省时省力。

4.1 Observe工作流程

Client Server │ │ │ CON [0x0001] GET /temperature │ │ Observe: 0 ← 注册观察 │ │ ───────────────────────────────────────> │ │ │ │ ACK [0x0001] 2.05 Content │ │ Observe: 12 ← 当前序列号 │ │ "22.5°C" │ │ │ │ │ │ CON [0x5a40] 2.05 Content │ │ Observe: 14 │ │ "23.8°C" │ │ │ │ │ │ HelloVerifyRequest (防DoS) │ │ │ │ │ │ ServerHello, Certificate* │ │ ServerKeyExchange*, CertificateRequest* │ │ ServerHelloDone │ │ │ │ │ │ [ChangeCipherSpec], Finished │ │ │

6.2 DTLS vs TLS对比

特性TLS 1.2DTLS 1.2
底层协议TCPUDP
记录层流式报文式(带序列号)
握手3次握手4次握手(加Cookie防DoS)
重传机制TCP处理DTLS自己处理
报文大小无限制需处理UDP分片

**⚠️ 注意:**DTLS握手比TLS更复杂,因为UDP不保证顺序和到达。DTLS需要处理丢包、重排序、重放攻击等问题。

七、Python aiocoap实战

理论讲完了,让我们动手写代码!这里使用Python的aiocoap库,它是目前最成熟的CoAP实现之一。

7.1 安装依赖

# 安装aiocoap pip install aiocoap # 如果需要DTLS支持 pip install aiocoap[dtls]

7.2 简单CoAP服务器

import asyncio import aiocoap import aiocoap.resource as resource from aiocoap import Message, Code class TemperatureResource(resource.Resource): """温度传感器资源""" def __init__(self): super().__init__() self.temperature = 22.5 async def render_get(self, request): """处理GET请求""" print(f"收到GET请求: {request.opt.uri_path}") payload = f'{{"temperature": {self.temperature}, "unit": "C"}}'.encode('utf-8') return Message( code=Code.CONTENT, payload=payload, content_format=50 # application/json ) async def render_put(self, request): """处理PUT请求(更新温度)""" try: data = json.loads(request.payload.decode('utf-8')) self.temperature = data.get('temperature', self.temperature) print(f"温度更新为: {self.temperature}°C") return Message(code=Code.CHANGED) except Exception as e: return Message( code=Code.BAD_REQUEST, payload=f'{{"error": "{str(e)}"}}'.encode() ) class ObservableTemperatureResource(resource.ObservableResource): """可观察的温度资源(支持Observe)""" def __init__(self): super().__init__() self.temperature = 22.5 self._task = None async def render_get(self, request): payload = f'{{"temperature": {self.temperature}, "unit": "C"}}'.encode('utf-8') msg = Message( code=Code.CONTENT, payload=payload, content_format=50 ) # 如果是Observe请求,设置observe选项 if request.opt.observe is not None: msg.opt.observe = self._get_next_observe_sequence() return msg def _get_next_observe_sequence(self): """获取下一个observe序列号(实际实现需要维护计数器)""" import time return int(time.time()) % (1

7.3 CoAP客户端

import asyncio from aiocoap import Context, Message, Code async def coap_get(uri): """发送CoAP GET请求""" protocol = await Context.create_client_context() request = Message(code=Code.GET, uri=uri) try: response = await protocol.request(request).response print(f"响应码: {response.code}") print(f"响应内容: {response.payload.decode('utf-8')}") return response except Exception as e: print(f"请求失败: {e}") finally: await protocol.shutdown() async def coap_put(uri, payload): """发送CoAP PUT请求""" protocol = await Context.create_client_context() request = Message( code=Code.PUT, uri=uri, payload=payload.encode('utf-8'), content_format=50 # application/json ) try: response = await protocol.request(request).response print(f"响应码: {response.code}") return response except Exception as e: print(f"请求失败: {e}") finally: await protocol.shutdown() async def coap_observe(uri, duration=30): """使用Observe模式订阅资源变化""" protocol = await Context.create_client_context() request = Message(code=Code.GET, uri=uri) request.opt.observe = 0 # 注册观察 observation_is_over = asyncio.Future() def observation_callback(response): if response.code.is_successful(): observe_seq = response.opt.observe if response.opt.observe else 'N/A' print(f"[Observe {observe_seq}] 收到更新: {response.payload.decode('utf-8')}") else: print(f"观察出错: {response.code}") observation_is_over.set_result(None) def error_callback(exception): print(f"观察出错: {exception}") observation_is_over.set_result(None) observation = protocol.request(request) observation.observation.register_callback(observation_callback) observation.observation.register_errback(error_callback) # 等待指定时间后取消观察 await asyncio.sleep(duration) observation.observation.cancel() await protocol.shutdown() print("观察已取消") async def discover_resources(uri="coap://localhost/.well-known/core"): """资源发现""" protocol = await Context.create_client_context() request = Message(code=Code.GET, uri=uri) try: response = await protocol.request(request).response print("发现的资源:") print(response.payload.decode('utf-8')) except Exception as e: print(f"发现失败: {e}") finally: await protocol.shutdown() async def main(): server_uri = "coap://localhost:5683" print("=== 1. 资源发现 ===") await discover_resources(f"{server_uri}/.well-known/core") print("\n=== 2. GET请求 ===") await coap_get(f"{server_uri}/temperature") print("\n=== 3. PUT请求 ===") await coap_put(f"{server_uri}/temperature", '{"temperature": 25.0}') print("\n=== 4. 再次GET验证更新 ===") await coap_get(f"{server_uri}/temperature") print("\n=== 5. Observe模式(观察15秒) ===") await coap_observe(f"{server_uri}/observable-temp", duration=15) if __name__ == '__main__': asyncio.run(main())

7.4 运行测试

# 终端1:启动服务器 python coap_server.py # 终端2:运行客户端测试 python coap_client.py # 或使用coap-client命令行工具(需要安装libcoap) coap-client -m get coap://localhost:5683/temperature coap-client -m put -e '{"temperature":25}' coap://localhost:5683/temperature coap-client -m get -s 15 coap://localhost:5683/observable-temp # 观察15秒

📦 源码获取

完整代码已包含在本文中,你也可以通过以下方式获取:

  • GitHub Gist: 搜索 “CoAP Python Examples”
  • aiocoap官方文档:https://aiocoap.readthedocs.io/- RFC 7252: Constrained Application Protocol

🤔 思考题

  • CoAP的四种消息类型(CON/NON/ACK/RST)分别适用于什么场景?能否举出具体的物联网应用例子?
  • 为什么CoAP选择基于UDP而不是TCP?这种设计带来了哪些优势和挑战?
  • 在Observe模式中,如果客户端网络断开后恢复,如何确保不会错过重要的状态更新?
  • 对比MQTT和CoAP,它们各自适合什么样的物联网场景?能否设计一个同时支持两种协议的系统架构?
  • DTLS握手比TLS多了一次往返(Cookie交换),这种设计解决了什么问题?

📚 系列文章预告

网络协议系列持续更新中,下一篇预告:

  • 第22篇:《MQTT协议深度解析——物联网的消息总线》
  • 第23篇:《LwM2M协议详解——设备管理的瑞士军刀》
  • 第24篇:《HTTP/3与QUIC——下一代Web协议》

点击关注,第一时间获取更新通知!

CoAP 物联网 IoT 嵌入式 低功耗 RESTful 网络协议

如果觉得本文对你有帮助,欢迎点赞、收藏、转发!

有任何问题或建议,欢迎在评论区留言讨论。让我们一起探索技术的无限可能!🚀

标签:IoT, 嵌入式, 物联网, RESTful, CoAP, 网络协议, 低功耗

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/9 14:19:25

从Excel到‘一张图’办案:手把手教你用AbutionGraph构建公安经侦知识图谱(含数据建模避坑指南)

从Excel到实战图谱:AbutionGraph构建公安经侦系统的全流程指南在公安经侦领域,数据往往以Excel表格、银行流水、通话记录等碎片化形式存在。这些数据背后隐藏着复杂的关联网络,传统分析方法需要人工比对多张表格,效率低下且容易遗…

作者头像 李华
网站建设 2026/6/9 14:17:17

ESP32定时器应用:ёRadio定时开关机功能实现

ESP32定时器应用:ёRadio定时开关机功能实现 【免费下载链接】yoradio Web-radio based on ESP32-audioI2S library 项目地址: https://gitcode.com/GitHub_Trending/yo/yoradio ёRadio是一款基于ESP32-audioI2S库开发的Web收音机项目,它不仅支持…

作者头像 李华
网站建设 2026/6/9 14:11:52

Java控制台匿名聊天室完整实现(含可运行工程+课程报告+实操截图)

本文还有配套的精品资源,点击获取 简介:一个纯Java SE开发的命令行匿名聊天室,不依赖任何第三方框架,基于Socket实现客户端-服务器通信。支持多用户同时在线、消息实时广播、服务端自定义监听端口,所有功能均在控制…

作者头像 李华
网站建设 2026/6/9 14:11:45

革命性零样本目标检测工具:grounding-dino-tiny完全指南

革命性零样本目标检测工具:grounding-dino-tiny完全指南 【免费下载链接】grounding-dino-tiny 项目地址: https://ai.gitcode.com/hf_mirrors/CICC/grounding-dino-tiny 你是否想过,让AI能够识别任何你描述的对象,而无需预先训练&am…

作者头像 李华
网站建设 2026/6/9 14:09:56

多阶段大模型工作流实现高精度文章摘要与翻译

1. 项目概述:为什么需要多阶段大模型工作流来处理文章摘要与翻译你有没有遇到过这样的场景:手头有一篇3000字的英文技术白皮书,领导下午三点前就要中文简报;或者你正在做跨境内容运营,每天要处理十几篇不同语种的行业快…

作者头像 李华