ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

RIOT 上基于 microcoap 构建 CoAP 服务器:native 平台测试与源码解析

RIOT 上基于 microcoap 构建 CoAP 服务器:native 平台测试与源码解析 RIOT 上基于 microcoap 构建 CoAP 服务器native 平台测试与源码解析【免费下载链接】RIOTRIOT - The friendly OS for IoT项目地址: https://gitcode.com/GitHub_Trending/riot/RIOT本文以 RIOT 仓库中的 tests/pkg/microcoap/README.md 为主线完整讲解如何基于 microcoap 第三方包在 RIOT 上实现一个 CoAP 服务器测试应用从 native 平台的编译、tap 接口配置、运行到使用 libcoap 命令行与 Copper 插件进行端到端测试并深入源码剖析端点注册、请求解析与响应构建的完整链路。读完本文你将掌握在 RIOT 上快速搭建并验证一个最小 CoAP 服务器的完整方法论以及 microcoap 与 RIOT 网络栈GNRC sock UDP的集成方式。应用概览一个最小可用的 CoAP 服务器测试程序tests/pkg/microcoap是一个专用于验证 RIOT 平台 CoAP 服务器能力的测试应用。按 README.md 的描述它的设计目的是帮助你开始用 RIOT 实现一个 CoAP 服务器底层通过 RIOT 的 sock socket API 使用 GNRC 网络协议栈。该应用的核心能力可归纳为三点监听标准的 CoAP UDP 端口5683等待并响应外部 CoAP 客户端的请求注册两个资源端点/.well-known/core服务发现返回 CoAP Link Format与/riot/board返回当前编译目标板名称如native通过sock_udp套接字完成 IPv6/UDP 数据包的接收、CoAP 报文解析、请求分发与响应回送。这一点可以从 microcoap_sock.c 中得到直接印证COAP_SERVER_PORT被定义为5683本地端点只指定AF_INET6地址族与端口因此服务器会监听所有已配置的 IPv6 地址。从源码结构看该测试目录下共四个文件职责划分清晰main.c程序入口打印 IPv6 地址信息后进入服务器主循环microcoap_sock.c基于sock_udp的阻塞式请求分发循环coap.c端点表endpoints定义与两个 GET 处理函数Makefile构建配置声明 microcoap 依赖与网络模块。注意README 中终端示例出现的路径examples/microcoap_server属于历史版本路径当前仓库中该应用的实际位置是tests/pkg/microcoap/。快速上手在 native 上编译与运行1. 编译应用在tests/pkg/microcoap/目录下执行$ make allmake all会完成两件事通过USEPKG microcoap拉取并构建 microcoap 第三方包见 Makefile同时编译测试应用本身。2. 创建 tap 虚拟网卡RIOT 的 native 移植通过 tap 设备接入宿主机网络。需要先创建一个 tap 接口并赋予当前用户权限$ sudo ip tuntap add tap0 mode tap user ${USER} $ sudo ip link set tap0 up3. 运行 RIOT 二进制$ make termmake term会以tap0为参数启动编译产物RIOT native 初始化完成后即开始监听。README 给出了典型启动输出核心部分/home/kaspar/src/riot/examples/microcoap_server/bin/native/microcoap_server.elf tap0 RIOT native interrupts/signals initialized. LED_GREEN_OFF LED_RED_ON RIOT native board initialized. RIOT native hardware initialization complete. main(): This is RIOT! (Version: 2015.12-devel-632-g8f451-booze-add_conn_coap_example) RIOT microcoap example application Waiting for address autoconfiguration... Configured network interfaces: Iface 5 HWaddr: 96:3c:18:1e:26:f7 MTU:1500 HL:64 RTR RTR_ADV Source address length: 6 Link type: wired inet6 addr: ff02::1/128 scope: local [multicast] inet6 addr: fe80::e42a:1aff:feca:10ec/64 scope: local inet6 addr: ff02::1:ffca:10ec/128 scope: local [multicast] inet6 addr: ff02::2/128 scope: local [multicast] inet6 addr: 2001:db8:1:0:e42a:1aff:feca:10ec/64 scope: global Waiting for incoming UDP packet...其中fe80::e42a:1aff:feca:10ec是链路本地地址scope: local用于宿主机与 RIOT 实例在 tap0 上的直接通信2001:db8:1:0:e42a:1aff:feca:10ec是全局作用域地址scope: global由路由通告自动配置产生输出末尾的Waiting for incoming UDP packet...对应 microcoap_sock.c 中循环体内的调试打印该宏默认关闭见下文 MICROCOAP_DEBUG 说明。启动阶段 main.c 会先xtimer_sleep(3)等待地址自动配置完成再调用netifs_print_ipv6()打印全部 IPv6 地址最后进入microcoap_server_loop()。使用外部 CoAP 客户端测试服务器就绪后可以用宿主机上的 CoAP 客户端发起请求。README 提供了两种经过验证的方式。方式一libcoap 命令行客户端libcoap 提供了coap-client命令行工具。以链路本地地址访问/riot/board资源将地址替换为你自己的# coap-client coap://[fe80::e42a:1aff:feca:10ec%tap0]/riot/board注意两点链路本地地址必须带%tap0区域标识指示 Linux 通过哪个接口发送数据包由于 IPv6 地址中含:地址必须用[ ]包裹。方式二CopperFirefox 插件 radvdCopper 是 Firefox 上经典的 CoAP 图形化测试插件但 RIOT 实例默认只有链路本地地址浏览器无法直接访问因此需要借助radvdRouter Advertisement Daemon让 tap0 上的节点自动配置出全局 IPv6 地址。需要准备Firefox 的 Copper 插件已安装的 radvd 守护进程重新make构建的应用。配置 /etc/radvd.conf在/etc/radvd.conf不存在则新建中写入以下内容interface tap0 { AdvSendAdvert on; MinRtrAdvInterval 3; MaxRtrAdvInterval 10; AdvDefaultPreference low; prefix 2001:db8:1:0::/64 { AdvOnLink on; AdvAutonomous on; AdvRouterAddr off; }; };关键参数含义AdvSendAdvert on在 tap0 接口上周期性发送路由通告MinRtrAdvInterval 3/MaxRtrAdvInterval 10RA 报文最小/最大发送间隔秒用于控制地址自动配置的收敛速度AdvDefaultPreference low本路由器的默认路由优先级prefix 2001:db8:1:0::/64块中的AdvAutonomous on允许节点通过 SLAAC无状态地址自动配置自行生成全局地址。这正是 RIOT 实例拿到2001:db8:1:0:e42a:1aff:feca:10ec一类全局地址的来源。可以用radvd -c校验配置文件语法然后启动$ sudo radvd通过 Copper 访问重新运行make term后接口输出中的全局作用域地址scope: global即为可访问地址。在 Firefox 地址栏输入coap://[2001:db8:1:0:e42a:1aff:feca:10ec]/riot/board将2001:db8:1:0:e42a:1aff:feca:10ec替换为你自己实例的全局地址。点击界面中央的绿色GET按钮后Payload文本框中应出现native——这正是/riot/board端点返回的板卡名由编译期宏RIOT_BOARD决定见下文源码解析。故障排查手动补充全局地址如果访问失败README 给出了备选方案——手动为 tap0 添加全局地址跳过 radvd 的自动配置流程$ sudo service radvd start $ sudo ip address add 2001:db8:1::a/64 dev tap0 $ make termip address add把主机侧 tap0 配成2001:db8:1::a/64再结合 radvd 的通告RIOT 侧即可在相同前缀下获得全局地址。源码级解析服务器究竟如何工作主流程等待自动配置后进入服务循环main.c 的逻辑非常精简打印横幅 →xtimer_sleep(3)等待地址配置 → 打印 IPv6 地址 JSON → 调用microcoap_server_loop()。由于服务循环是while (1)死循环main末尾的return 0实际不会执行。请求处理循环sock_udp microcoap 的组合microcoap_sock.c 是整个服务器的核心其数据通路可拆解为五个步骤#define COAP_SERVER_PORT (5683) static uint8_t _udp_buf[512]; /* udp read buffer (max udp payload size) */ uint8_t scratch_raw[1024]; /* microcoap scratch buffer */ coap_rw_buffer_t scratch_buf { scratch_raw, sizeof(scratch_raw) };创建套接字sock_udp_create(sock, local, NULL, 0)local仅绑定 IPv6 与 5683 端口不限定远端阻塞接收sock_udp_recv(..., SOCK_NO_TIMEOUT, remote)无限期等待 UDP 数据报返回后remote中携带对端地址解析 CoAP 报文coap_parse(pkt, _udp_buf, n)把原始字节解析为coap_packet_t分发请求coap_handle_req(scratch_buf, pkt, rsppkt)依据端点表查找匹配的处理函数并填充响应报文回送响应coap_build(_udp_buf, rsplen, rsppkt)将响应序列化回字节流再经sock_udp_send(sock, _udp_buf, rsplen, remote)发回对端。从源码结构可以推断该循环刻意保持了极简形态所有错误分支仅打印调试信息后continue不涉及连接状态管理——这正体现了 CoAP 基于无连接 UDP 的设计哲学。缓冲区方面UDP 读取缓冲为 512 字节对应 IPv6 UDP 单包上限microcoap 的 scratch 缓冲为 1024 字节用于构造响应时的临时空间。端点表与响应构建coap.c 通过 microcoap 的端点表机制注册资源const coap_endpoint_t endpoints[] { { COAP_METHOD_GET, handle_get_well_known_core, path_well_known_core, ct40 }, { COAP_METHOD_GET, handle_get_riot_board, path_riot_board, ct0 }, /* marks the end of the endpoints array: */ { (coap_method_t)0, NULL, NULL, NULL } };每个端点由四元组构成HTTP 方法此处均为 GET、处理函数、路径path_well_known_core为{ 2, { .well-known, core } }path_riot_board为{ 2, { riot, board } }其中count2表示两级路径段、Core 属性描述ct40表示返回内容为 Link Formatct0表示 text/plain。数组以全零哨兵项结尾。handle_get_well_known_corecoap.c遍历端点表将每个带core_attr的端点序列化为 RFC 6690 风格的 Link Format 字符串例如/.well-known/core;ct40,/riot/board;ct0最终调用coap_make_response()以COAP_RSPCODE_CONTENT和COAP_CONTENTTYPE_APPLICATION_LINKFORMAT回包handle_get_riot_boardcoap.c将编译期宏RIOT_BOARD如native、nucleo-f334r8直接作为响应体以COAP_CONTENTTYPE_TEXT_PLAIN返回。这就是 Copper 中GET之后 Payload 显示板卡名的原理。microcoap 包在 RIOT 中的集成tests/pkg/microcoap依赖的 microcoap 是一个轻量级 CoAP 协议栈第三方包其构建信息记录在 pkg/microcoap/MakefilePKG_NAMEmicrocoap、PKG_LICENSEMIT并锁定在固定 commitef272895925f0d4c563725fe0102966f544a0fdc上。RIOT 通过pkg/pkg.mk的标准流程下载源码、套用 pkg/microcoap/patches 补丁后编译头文件搜索路径则由 pkg/microcoap/Makefile.include 中的INCLUDES -I$(PKGDIRBASE)/microcoap提供。pkg/microcoap/patches 目录下的补丁揭示了 RIOT 对上游 microcoap 的关键适配了解这些对排查问题很有价值0002-Add-RIOT-Makefile.patch将上游自带、面向宿主机的 Makefile含-DDEBUG、.d依赖生成、coap可执行文件等整体替换为include $(RIOTBASE)/Makefile.base使其并入 RIOT 的统一构建体系0003-change-flag-from-DEBUG-to-MICROCOAP_DEBUG.patch把调试开关从通用的DEBUG改名为MICROCOAP_DEBUG避免与 RIOT 自身的调试宏冲突同时把coap_dump/coap_dumpPacket在未开启调试时收敛为空宏——这解释了为何示例中那些coap_dump()调用默认不产生输出0004-Increment-MAX_SEGMENTS.patch允许通过编译选项覆盖路径段数上限MAX_SEGMENTS默认 2即/foo/bar两级路径如需更深路径可-DCOAP_MAX_SEGMENTSvalue扩展。构建配置与低内存板卡适配测试应用的 Makefile 完整展示了 RIOT 应用所需的最小网络模块组合USEMODULE netdev_default USEMODULE auto_init_gnrc_netif USEMODULE gnrc_ipv6_default USEMODULE gnrc_icmpv6_echo USEMODULE sock_udp USEMODULE xtimer USEPKG microcoap其中netdev_default与auto_init_gnrc_netif负责拉起网卡并自动初始化 GNRC 网络接口gnrc_ipv6_default提供 IPv6 协议栈含 6LoWPAN——如 Makefile 注释所述若板卡带 IEEE802.15.4 设备会自动引入 6LoWPAN 适配gnrc_icmpv6_echo提供 ping 能力便于连通性测试sock_udp正是服务器循环所依赖的 sock API。针对 RAM 紧张的板卡如nucleo-f334r8Makefile 提供了低内存分支追加prng_minstd用轻量伪随机数生成器替代默认实现并通过-DCONFIG_GNRC_PKTBUF_SIZE1000将 GNRC 数据包缓冲从默认值压缩到 1000 字节。同时 Makefile.ci 中维护了一份BOARD_INSUFFICIENT_MEMORY列表含 arduino-uno、bluepill-stm32f030c8、telosb 等 30 余款板卡CI 会跳过这些内存不足的目标——这说明该示例对板卡 RAM 有一定要求选择实机部署时需留意。小结通过 tests/pkg/microcoap/README.md 与配套源码你可以看到一条完整的 CoAP 服务器落地路径在 native 上编译、配置 tap 接口、用 libcoap 与 Copper 验证再到源码层理解sock_udp收发、microcoap 的coap_parse/coap_handle_req/coap_build处理链与端点注册机制。这套最小实现既是学习 RIOT 网络栈的绝佳起点也是后续移植到真实板卡、扩展更多 CoAP 资源如 PUT/POST 写操作、Observe 观察订阅时可直接复用的骨架。【免费下载链接】RIOTRIOT - The friendly OS for IoT项目地址: https://gitcode.com/GitHub_Trending/riot/RIOT创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表