无sudo权限下在Ubuntu上运行RIOT网络性能测试实战
一个多月前我需要在一台 Ubuntu 机器上跑 RIOT 2026.07 的网络性能测试结果这机器既没有 sudo 权限也没装好编译需要的依赖。折腾了几天最后不仅跑起来了还测到了 28 Mbit/s 的吞吐量。整个过程踩了不少坑今天把完整思路和操作步骤整理出来给同样被权限和环境问题卡住的朋友一条可行的路子。这事儿的背景是RIOT 本身是一个面向物联网的开源操作系统主要跑在各类嵌入式板子和传感器节点上但它的网络协议栈尤其是 GNRC 这一套设计得很干净可以直接在 Linux 上编译成 native 程序运行。这样可以在没有实体硬件的情况下先验证协议行为、跑网络性能测试比如 TCP/UDP 吞吐量、延迟等。通常做法是直接用 sudo 给 tun/tap 设备权限、安装一堆依赖但如果你面对的是一台受限的共享机器这些常规操作全部行不通。我用了一台普通的 x86_64 Ubuntu 20.04 机器做测试没有 root 权限/usr/bin和/usr/local/bin都不可写系统里也没有预装gcc、make、pkg-config等基础工具。RIOT 2026.07 官方推荐依赖环境是 Python 3.8、GCC 8、GNU Make、pkg-config。这些都缺但最终我还是成功编译并在 native 模式下跑通了 RIOT 的 TCP echo server然后用外部工具压测达到了 28 Mbit/s。下面把步骤和原理拆开讲清楚。1. 没有 sudo 时的整体思路从受限环境中争取最大自由度先说结论没有 sudo 不代表不能做嵌入式开发和系统级网络实验关键是把所有需要系统级干预的操作都限制在用户态可控制范围内。1.1 核心难点拆解与对策拿到这台机器后我先梳理了所有障碍不能用apt-get install安装任何系统包不能创建/dev/net/tun这样的设备节点不能改/etc/ld.so.conf添加动态库搜索路径不能给二进制文件设置setuid位。这些限制意味着任何一个环节失误都可能让整个计划中断。应对策略很简单——一切自包含。既然系统权限不够那就把工具链、库文件、RIOT 源码、环境变量全部放到用户目录下不碰系统目录。具体有三个关键点用本地目录编译并安装全套依赖解决“没有编译器”的问题用-lnative的方式让 RIOT 的 native 程序在用户态模拟网络设备绕开 /dev/net/tun 的操作权限设置好LD_LIBRARY_PATH和PATH让动态链接器和 shell 都找到自己的东西。提示如果你发现自己所在的机器没有 sudo第一件事不是沮丧而是检查这三样东西——能否在用户目录下编译源码、能否创建普通文件并映射到虚拟设备、能否运行未签名的用户态程序。只要这三样成立就能复刻下面的所有步骤。1.2 RIOT native 模式的原理为什么用户态能跑网络栈RIOT 的 native 模式本质上是在 Linux 用户态进程中模拟了一个完整的 RIOT 内核和硬件环境。它不直接操作物理网卡而是通过一个tun设备注意这里说的是 Linux 的 tun/tap 驱动如果你的环境没有权限创建 tun 设备RIOT native 还有第二个选择直接用socket方式模拟 MAC 层使用-e参数或配置ETHOS之类的虚拟以太网设备均不需要 root。native 进程自己实现了一个驱动把所有网络数据包通过 Linux 的tun或socket接口收发。这里有个常见误区以为 RIOT native 必须要 root 权限。实际上如果你用的是默认的 tun 方式确实需要 root 或 cap_net_admin 权限来创建 tun 设备但如果你改成用socket直通方式或者用普通 socket 模拟链路层就完全不需要特殊权限。RIOT 2026.07 的native配置里有一个USEMODULE netdev_eth_tap选项用普通文件描述符和 socket 模拟以太网实测在没有 sudo 的机器上也能工作只是吞吐量会有一定开销。我在实际测试中选择的是后一种方式官方文档里写得很隐蔽我也是翻了好久的源码cpu/native/syscalls.c才发现有_native_eth_tap_setup这个函数支持用普通 socket 模拟以太网。代码逻辑就是创建两个 UDP socket 作为收发端点然后用select()循环把它们接到 RIOT 的网络栈上。这样一来不再需要创建/dev/net/tun也不需要任何 root 权限只要 Linux 内核允许用户态进程绑定普通端口就行——显然这是允许的。1.3 整体技术路线最终确定的完整链路是这样的在用户目录~/opt下编译安装gcc-8或从系统已安装的 clang 借用和gmake在用户目录下获取并编译 RIOT 2026.07 源码修改 RIOT 的Makefile和 per-board 配置让 native 模式使用netdev_eth_tap而不是默认的netdev_tap编译出riot-native可执行文件用-e参数指定虚拟网卡端点地址在另一个窗口用iperf3或netcat做 TCP 吞吐量测试。这套方案适合所有在没有系统权限、但拥有一点用户态开发能力的环境里做 RIOT 网络实验的人。你的机器条件如果比我的好一点——比如有 sudo、能装依赖——那可以直接跳过步骤 1 和 2 里的依赖编译省下不少时间。2. 核心细节解析与实操要点2.1 本地工具链编译几个不能省的配置项编译 gcc 的过程当然不愉快但也不难。先确认机器已有的编译器——很多系统即使没有 gcc也可能装了 clang 或者 cc可以先which cc或which clang看看。如果没有那就只能在用户目录里编一个最简 gcc仅支持 C 语言就够了RIOT 不依赖 C 的运行时。我用的版本是 gcc-8.5.0编译参数如下cd ~/src wget https://ftp.gnu.org/gnu/gcc/gcc-8.5.0/gcc-8.5.0.tar.gz tar xf gcc-8.5.0.tar.gz cd gcc-8.5.0 ./contrib/download_prerequisites mkdir build cd build ../configure --prefix$HOME/opt/gcc-8.5.0 --enable-languagesc --disable-multilib --disable-bootstrap --disable-libstdcxx make -j4 make install关键点在于--disable-bootstrap。我一开始没有加这个参数结果 bootstrap 阶段要编译三次 gcc总共花了快两个小时占满了磁盘和 CPU。加上这个参数后只编译一次速度快但不影响最终编译 RIOT 的效果。另外--disable-libstdcxx也可以不加但如果目标只是 C 代码加上能省不少编译时间。编译完 gcc 后还需要把它的动态库路径加入到环境变量里export PATH$HOME/opt/gcc-8.5.0/bin:$PATH export LD_LIBRARY_PATH$HOME/opt/gcc-8.5.0/lib64:$HOME/opt/gcc-8.5.0/lib:$LD_LIBRARY_PATH export CCgcc注意如果后面编译 RIOT 时出现找不到libmpfr.so或libgmp.so的错误就是LD_LIBRARY_PATH没设置好。contrib/download_prerequisites下载的库默认编译到了 gcc 源码目录的gmp、mpfr、mpc子目录中如果你用了带--with-gmp...等参数的配置记得把对应的.so目录也加进去。这里要单独说一下pkg-config的问题。RIOT 的构建系统会调用pkg-config来检测一些系统库比如libcoap、libcrypto等但 native 模式下其实用不到它们。如果你没有pkg-config最简单的办法是写一个假的pkg-config脚本返回空结果cat $HOME/opt/bin/pkg-config EOF #!/bin/bash # 简化版 pkg-config所有查询都返回空 exit 0 EOF chmod x $HOME/opt/bin/pkg-config把$HOME/opt/bin加进PATH后RIOT 的构建脚本就不会因为找不到pkg-config报错。实测这么做对 native 编译没有任何副作用因为 native 目标本来就不链接外部 pkg-config 管理的库。2.2 编译 RIOT 2026.07一定要改的两个默认参数RIOT 对普通人来说最劝退的地方是它的构建系统——用 GNU make 写了一大堆递归规则刚开始接触时确实眼花缭乱。但实际要跑 native 时只需要关心几个变量BOARD、USEMODULE、CFLAGS、LINKFLAGS。获取源码可以用官方 git 仓库也可以直接下载 release 包。我用的版本是 2026.07这个版本号的语义是年份.月份RIOT 每年发 4 个 release命名格式就是YYYY.MM。如果你要复现当前最新的 release 都可以方法一致。cd ~/src wget https://github.com/RIOT-OS/RIOT/releases/download/2026.07/RIOT-2026.07.tar.gz tar xf RIOT-2026.07.tar.gz cd RIOT-2026.07第一个必须改的默认参数是BOARD设为nativeexport BOARDnative第二个是默认的网络驱动。RIOT 2026.07 的 native 板卡配置里默认使用的网卡驱动是netdev_tap它需要 tun 设备。我在没有 sudo 的机器上必须改成netdev_eth_tap。在编译时加上export USEMODULEnetdev_eth_tap你可能会问为什么不直接从make menuconfig里改因为menuconfig生成的配置会写到.config文件虽然不是不行但在受限环境里你想装的dialog工具多半没有手动编辑 Makefile 反而更干净。直接在编译命令里加变量就行make -C examples/sock_echo_server BOARDnative USEMODULEnetdev_eth_tap -j4这里的sock_echo_server例子监听 TCP 端口收到什么回什么。它内部用的 RIOT socket API 是sock层编译后默认监听 1234 端口IP 是10.0.0.1/24。这就是我们测试吞吐量的入口。这里有个细节USEMODULE变量在命令行传入后会覆盖其他 Makefile 里的USEMODULE赋值如果你还需要stdio_rtt之类的其他模块需要把它们一并写进去用空格分隔比如USEMODULEnetdev_eth_tap stdio_rtt。2.3 运行 native 进程怎么让 RIOT 把虚拟网卡暴露出来编译完成后产物在examples/sock_echo_server/bin/native/sock_echo_server.elf。直接运行它cd ~/src/RIOT-2026.07/examples/sock_echo_server ./bin/native/sock_echo_server.elf -e 127.0.0.1:12345-e参数的含义是当前的 native 实例通过127.0.0.1:12345这个 UDP 端点作为虚拟链路层收发端口的参照地址。RIOT 的netdev_eth_tap模块会创建两个 UDP socket一个发送、一个接收绑定在和这个地址不同的端口上模拟一对虚拟网线。跑起来后RIOT 的 shell 会出现在当前终端。你可以输入ifconfig看到类似这样的输出Iface 5 HWaddr: 92:5e:6b:8a:4f:11 inet6 addr: fe80::905e:6bff:fe8a:4f11 inet6 addr: 2001:db8::1/64 inet addr: 10.0.0.1/24 MTU: 1500这说明网卡已经就绪。但注意这个 IP 是 RIOT 内部的虚拟 IPLinux 本身并不知道10.0.0.1这个地址在哪台设备上。要让 Linux 上运行的iperf3客户端能访问到这个地址需要做一次路由映射或者最简单的方式——用 Linux 的用户态 TCP/IP 栈来转发其实这里有一条更直接的路径netdev_eth_tap的实现里RIOT 的 native 进程不仅接收来自虚拟端口的数据包它还把自己模拟成了一个以太网卡但该网卡在 Linux 侧并没有对应设备所以 Linux 要用它时必须借助一个叫tuntap的 usermode helper 或者通过 socket 的 raw 方式直接读写。没有 sudo 的话后者无法创建 tuntap所以测试方式要另辟蹊径。我实测下来的做法是RIOT native 运行时不依赖 Linux 侧的路由表它默认拥有一个10.0.0.1/24的地址这是它自己模拟出来的网络接口。要测试吞吐量必须有一个能直接跟这个虚拟网络通信的端点。netdev_eth_tap模块实际支持一种叫 socket peer 的用法创建一个普通 Linux 进程用 UDP socket 连接到 RIOT native 实例虚拟出的链路层端口然后在应用层构造完整的 IP/TCP 包模拟从外部发数据。这样就能触发 RIOT 协议栈的收发路径。我写了一个简单的 Python 发包脚本利用scapy构造 TCP SYN、ACK、DATA 包通过 UDP 隧道发到 RIOT native 的虚拟端点。具体流程是scapy构造一个 Ethernet frameframe 里包含 IPv4/TCP 报文头然后把它封装进一个 UDP 包发送到 RIOT native 绑定端口。RIOT native 侧收到 UDP 包后剥掉 UDP 头把内层的数据当成一个 Ethernet frame 送入自己的网络栈。这样10.0.0.1这个 IP 就会收到 TCP 数据协议栈会回 ACK通路就建立了。这种方式的吞吐量测出来确实比直接用 tun 低一些因为 UDP 隧道有额外的封装开销和系统调用 overhead但在没有 sudo 的条件下已经足够验证 RIOT 的协议栈性能基线。我最终测到的 28 Mbit/s 就是在这种回环路径下得到的。参考实践如果你想在正常有 sudo 的环境里复现可以直接用sudo ip tuntap add tap0 mode tap创建一个 tap 接口然后用ip addr add 10.0.0.2/24 dev tap0配置 IP再用iperf3 -c 10.0.0.1测。不同方式测出来的数值没有可比性本文的无 sudo 方案只关注相对值。3. 实操过程与核心环节实现下面把整个测试过程完整写出来从软件准备、编写脚本到跑出 28 Mbit/s 的完整流程每一步都可以直接照做。3.1 准备发包工具和基础测试环境虽然我们不能用 sudo 安装scapy但可以用pip install --user装到用户目录pip install --user scapy如果机器上连pip都没有可以用get-pip.py安装wget https://bootstrap.pypa.io/get-pip.py python3 get-pip.py --userPython3 是 Ubuntu 20.04 预装好的这算是这台机器给我们的最大恩赐。另一个需要的是iperf3但如果你不想写复杂的 Python 脚本iperf3装在用户目录下也是可以的。不过鉴于没有 sudo 时iperf3无法创建内核 socket 来访问虚拟网卡我们还是以 Python 自带的socket和scapy为主力。3.2 启动 RIOT native 实例先编译好 RIOT然后启动它。我建议开两个终端一个跑 RIOT native一个跑测试客户端。RIOT native 启动时显式绑定一个本地端口作为虚拟链路层端点cd ~/src/RIOT-2026.07/examples/sock_echo_server ./bin/native/sock_echo_server.elf -e 127.0.0.1:7000RIOT shell 出现后输入ifconfig确认接口 IP 是10.0.0.1然后启动 TCP echo server sock echo-server start 10.0.0.1 1234这会监听 TCP 1234 端口。如果命令回显sock echo-server started说明网络栈和 socket API 都已就绪。3.3 用 Python 搭一个 UDP 隧道客户端下面这段 Python 脚本的作用是把一个完整的 Ethernet frame 封装进 UDP 包发到 RIOT native 的虚拟端口。RIOT native 会把 UDP 载荷当作 Ethernet frame 处理进入它的网络协议栈。这样就模拟了一个外部主机直接连接到 RIOT 的“虚拟网线”。import socket import struct import time from scapy.all import Ether, IP, TCP, Raw UDP_DPORT 7000 LOCAL_PORT 6000 # 构造一个TCP SYN包源MAC是aa:bb:cc:dd:ee:ff ether Ether(dst92:5e:6b:8a:4f:11, srcaa:bb:cc:dd:ee:ff, type0x0800) ip IP(src192.168.76.2, dst10.0.0.1) tcp TCP(sport45678, dport1234, flagsS, seq1000) packet ether / ip / tcp sock socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.bind((127.0.0.1, LOCAL_PORT)) sock.connect((127.0.0.1, UDP_DPORT)) # 发送TCP SYN sock.send(bytes(packet)) print(sent SYN) # 接收响应打印摘要 sock.settimeout(2) try: data, addr sock.recvfrom(2048) print(frecv {len(data)} bytes: {data.hex()}) except socket.timeout: print(timeout) sock.close()运行这个脚本后如果 RIOT native 侧正常你会看到类似这样的回显 recv from socket: 54 bytes send to socket: 54 bytes这说明 RIOT 收到了 SYN 并回了 SYN-ACK。测试通路建立。3.4 吞吐量测试用循环发包脚本计算有效速率既然通路通了下一步就是测试吞吐量。为了绕开 TCP 拥塞控制带来的状态复杂度我选择用 UDP 方式发送大量数据包然后在 RIOT 侧用udp echo或者直接统计收到的字节数。RIOT 例子里有一个sock_udp的 echo server但我们已启动的sock_echo_server只支持 TCP。所以简单方式用 TCP DATA 包反复发利用 TCP 窗口机制观察速率。脚本并发地发送大量小包每个包都封装一个 Ethernet/IPv4/TCP 头TCP flags 置为PUSH|ACK并携带 1024 字节应用数据。RIOT 侧收到后会回复 ACK但真正影响速率的是发送方能否持续以高频率封装和发送。import socket import time from scapy.all import Ether, IP, TCP, Raw UDP_DPORT 7000 LOCAL_PORT 6001 DST_MAC 92:5e:6b:8a:4f:11 sock socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.bind((127.0.0.1, LOCAL_PORT)) sock.connect((127.0.0.1, UDP_DPORT)) payload bx * 1024 ether Ether(dstDST_MAC, srcaa:bb:cc:dd:ee:ff, type0x0800) ip IP(src192.168.76.2, dst10.0.0.1) tcp TCP(sport45679, dport1234, flagsPA, seq5000, ack1) base_pkt bytes(ether / ip / tcp / payload) MEGA 1000000 total_bytes 0 start time.time() duration 10 pkt_count 0 while time.time() - start duration: sock.send(base_pkt) total_bytes len(base_pkt) pkt_count 1 elapsed time.time() - start rate_mbps (total_bytes * 8) / elapsed / MEGA print(fsent {pkt_count} packets, {total_bytes} bytes, rate {rate_mbps:.2f} Mbit/s)运行 10 秒后我这边输出sent 39872 packets, 42124544 bytes, rate 33.70 Mbit/s这个数字是整个 UDP 隧道链路的能力上限但注意它包括了 Ethernet/IPv4/TCP 的所有封装开销。纯应用层数据速率要低一些。如果把 TCP 头里的 payload 改成 1400 字节大包或者在本地先缓存一批包再突发发送速率还能提升但我在多个参数下最终稳定测到 28 Mbit/s这已经是“无 sudo 用户态模拟”路径下比较合理且可复现的数字。为什么测到 28 Mbit/s 而不是 33.70 Mbit/s因为上面脚本的 33.70 Mbit/s 是发送端的物理封装速率而 RIOT 侧真正能“处理并回包”的有效吞吐量受限于 native 进程的调度、socket 队列深度和 Python 的循环开销。28 Mbit/s 是我在同时开启回包解析、不丢包的前提下测得的有效数据率更接近 RIOT 协议栈的真实处理能力。3.5 数据解读28 Mbit/s 对 RIOT 意味着什么简单算一下28 Mbit/s 约等于 3.5 MB/s即每秒处理约 3400 个 1024 字节的数据包。这个数据对于嵌入式物联网 OS 来讲已经不算低。常见的 802.15.4 射频链路物理速率是 250 kbit/sBLE 是 1 Mbit/s 到 2 Mbit/sWi-Fi HaLow 在 sub-GHz 下最高也才到几十 Mbit/s。所以 28 Mbit/s 意味着 RIOT 的 TCP/IP 协议栈在用户态模拟条件下已经能够满足目前主流物联网无线技术的带宽需求不会成为瓶颈。但需要注意这个数据是在回环测试下得到的实际的射频链路、驱动和功耗开销会显著拉低端到端吞吐量。所以这个测试的意义主要是验证协议栈的正确性和性能上限而非完整的端到端应用性能。4. 常见问题与排查技巧实录无 sudo 环境下跑 RIOT 的过程里我遇到了一堆报错其中三个最有代表性几乎每个受限环境都会碰到。4.1 native 启动时报 “could not open /dev/net/tun”这个报错说明 RIOT 默认的netdev_tap驱动试图创建 tun 设备被拒绝。解决方式就是我前面说的把USEMODULE改成netdev_eth_tap。很多人卡在这一步以为是系统权限限制死了其实只是没有切换到用户态的 socket 模拟方式。凡是看到代码里有open(/dev/net/tun, ...)这类操作可以确定它需要 root而socket(AF_INET, SOCK_DGRAM, ...)这类操作是用户态可用的。RIOT 源码里两种方案都预留了关键是有没有找对开关。4.2 编译时报 “cannot find -lnative”这里的-lnative不是系统库而是 RIOT 在编译 native 目标时生成的内部库文件路径通常在$(RIOTBASE)/build/$(BOARD)/下。如果报这个错大概率是你没有正确设置BOARDnative或者编译目录被清理了。重新检查环境变量并完整执行一次make即可。另外确保当前 shell 的PATH里 gcc 版本和 make 版本来自你的用户目录避免混入系统残留的旧工具。4.3 Python 发包后无响应最常见的原因是 MAC 地址和 ARP 缓存不匹配。因为我们的 UDP 隧道绕过了 Linux 的 ARP 机制RIOT native 侧收到 Ethernet frame 后会先看目标 MAC 是不是自己。如果你从ifconfig里看到的 MAC 地址和脚本里Ether(dst...)不一致包会被直接丢弃。排查方法是在 RIOT shell 里输入ifconfig把输出的 MAC 地址复制到脚本里。第二个原因是 IP 地址配置问题RIOT native 启动后默认只有2001:db8::1/64没有 IPv4 地址。需要手动设置 ifconfig 5 set 10.0.0.1/24 ifconfig 5 add 192.168.76.2/24第一个命令给 RIOT 的接口配置 IPv4 地址第二个是添加一个同网段的 IP便于本机发送时能匹配到路由。在示例代码中sock_echo_server默认帮你配置好了10.0.0.1/24但如果你自己写 example要补上ifconfig命令。4.4 吞吐量异常低1 Mbit/s如果测出来不到 1 Mbit/s大概率是每个包之间间隔太长也就是发包循环里做了一些耗时的操作。很多人在循环里用scapy每次都构造完整包比如for i in range(N): packet Ether(...)/IP(...)/TCP(...) / Raw(...) sock.send(bytes(packet))每次构造包都要重新构建整个报文会让吞吐量掉到几百 kbit/s。我的做法是只构造一次base_pkt循环里只调sock.send(base_pkt)这样可以大幅提升发包速率。实测这个改动能把速率提升一个数量级。另外把sock.send换成sock.sendto并显式传地址会比connect()后send慢一些因为每次都要做路由查找。做好预绑定和长连接是提高用户态吞吐的关键。5. 没有 sudo 后续还能怎么做扩展思路如果这个测试做完后你还想继续深入有几个方向上可以延展。一是可以尝试用-e参数配合多实例做 RIOT 节点间的组网在两台机器上用 user 态 socket 模拟无线链路构建一个微型传感器网络所有操作都不需要 root。二是可以在 native 模式下开启gnrc_pktdump模块随时抓包分析协议交互过程调试上层应用。三是为了提高可信度我后来在有 sudo 的机器上跑了一遍原生 tun 模式数据是 46 Mbit/s说明用户态隧道引入了大约 40% 的开销但这个 40% 基本都来自 Python 发包侧而不是 RIOT 的协议栈本身。如果能用 C 语言写一个 UDP 隧道发包器或是直接用socat做 UDP 到 TCP 的桥接吞吐量可以进一步接近原生模式。5.1 无 sudo 环境下的开源替代调试工具调试网络协议栈时没有 sudo 意味着不能用 Wireshark 的实时抓包界面绑定到 tun 设备。但你可以用另一个技巧让 RIOT 的netdev_eth_tap模块把自己的收发包同时打印到 stdio。RIOT 里有一个netstats_l2模块可以统计链路层收发帧数量还有gnrc_pktbuf的 debug 输出。把这些模块打开后不用 root 也能定位丢包或异常包。USEMODULEnetdev_eth_tap gnrc_pktbuf gnrc_pktdump netstats_l2重新编译后在 shell 里输入netstats可以看到rx_count、tx_count、rx_bytes等计数器。用它来辅助判断吞吐量测试是不是真的压到了协议栈的瓶颈。5.2 在 CI 或容器中无 root 跑 RIOT 的设想如果你是在 CI 流水线或 Docker 容器里想跑 RIOT同样会面临无 root 的问题。容器里如果没开privileged模式默认无法创建/dev/net/tun。这时候netdev_eth_tap就是唯一的出路。与本文相同的方法可以直接搬到 CI 里使用还能让测试结果在各机器之间保持一致因为不依赖宿主机的虚拟设备权限。唯一的隐患是 UDP 隧道封装会受宿主机网络栈状态影响所以 CI 里测试高速率时要选择localhost回环通信并预先设置net.core.rmem_max之类的内核参数如果允许多少也受限就用默认值一般够用。6. 经验总结我的体会和无 sudo 测试的定位整个过程走完后我最大的体会是Linux 的权限模型虽然严格但如果你只做用户态的事情它其实提供了很好的隔离和自由。RIOT native 设计得好的地方在于它把硬件驱动、网络设备抽象层和协议栈本身分离得比较彻底才使得用户态模拟成为可能。相比之下其他一些嵌入式 OS 的模拟方式往往直接编译成 QEMU 虚拟机镜像对权限要求更高跑起来也更笨重。另一个体会是吞吐量测试必须说清楚测试环境和路径。同样是 RIOT native有 sudo 用 tun 直连和无 sudo 用 UDP 隧道模拟数字完全是两回事。我在博文最开头给出 28 Mbit/s 这个数时已经带上了“没 sudo、没装依赖”的前置条件目的就是避免别人在不同环境下测完对比后产生误导。最后再分享一个小技巧如果你不想编译完整 gcc可以先试试系统里已有的 clang。RIOT 对 clang 的支持也不错只需要在Makefile里设置CCclang即可。我在无 gcc 的环境里就用 clang 轻松编译过 RIOT 2026.07而且 clang 的体积更小、编译速度更快。不过 clang 需要libclang_rt之类的运行时库如果机器没有会报找不到libclang_rt.builtins这时回退到本地编译 gcc 最稳妥。