ARTICLE DETAIL

资讯详情

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

Zephyr + Mongoose HTTP/HTTPS 客户端实战:基于 QEMU 虚拟板卡的无硬件开发指南

Zephyr + Mongoose HTTP/HTTPS 客户端实战:基于 QEMU 虚拟板卡的无硬件开发指南 嵌入式网络通信物联网【免费下载链接】mongooseEmbedded web server, with TCP/IP network stack, MQTT and Websocket项目地址https://gitcode.com/gh_mirrors/mon/mongoose点击查看免费下载导读本文以仓库中的 tutorials/zephyr/http-client 示例为骨架完整讲解如何在 Zephyr RTOS 上使用 Mongoose 嵌入式网络库编写 HTTP/HTTPS 客户端包括工程结构与关键源码解析、prj.conf/overlay-e1000.conf网络与 TLS 配置逐项说明以及如何借助 Docker QEMU TUN/TAP 在无实体开发板的情况下完成构建、运行与调试。读完本文你将能够基于当前仓库直接复现一个 Zephyr 平台的 HTTPS 客户端并将其构建流程迁移到任意 Zephyr 目标板。说明原文档所链接的详细教程为外部在线资源本文所有事实均以当前仓库内tutorials/zephyr/目录的实际文件为准README、Makefile、prj.conf、overlay-e1000.conf、src/main.c等并辅以 Mongoose 核心源码佐证。一、示例概览与仓库结构该示例位于 tutorials/zephyr/http-client/目录结构如下tutorials/zephyr/http-client/ ├── CMakeLists.txt # Zephyr CMake 工程定义 ├── Makefile # 基于 Docker 的构建/运行/烧录/调试入口 ├── README.md # 构建与模拟运行说明 ├── overlay-e1000.conf # QEMU e1000 网卡模拟配置覆盖层 ├── prj.conf # Zephyr 内核、网络栈与 mbedTLS 配置 └── src/ ├── certs.h # 内嵌的 DigiCert 根证书PEM ├── main.c # HTTP/HTTPS 客户端主程序 └── mongoose_config.h # Mongoose 平台与 TLS 后端选择示例的工作方式程序启动后等待 Zephyr 网络栈 L4 层连接就绪DHCP 获取 IP随后通过 SNTP 同步系统时间HTTPS 证书校验需要有效时间最后调用mg_http_connect()对https://example.org/发起一次 GET 请求可通过修改s_post_data切换为 POST收到完整 HTTP 响应后打印并退出事件循环。本示例同样适用于同目录下的其他 Zephyr 示例http-server、websocket-server、mqtt-aws-client、device-dashboard它们的构建方式完全一致——原文档也明确指出Device Dashboard 教程中的构建说明是通用的。二、从源码看客户端工作流程src/main.c是整个示例的核心它演示了 Mongoose 在 Zephyr 上的标准用法先等网络就绪再进事件循环。2.1 等待 L4 网络就绪Zephyr 的网络接口初始化是异步的直接发起连接会失败。示例使用 Zephyr 网络管理框架net_mgmt来同步等待K_SEM_DEFINE(run, 0, 1); static void zeh(struct net_mgmt_event_callback *cb, #if ZEPHYR_VERSION_CODE 0x40200 uint32_t mgmt_event, #else uint64_t mgmt_event, #endif struct net_if *iface) { if (mgmt_event NET_EVENT_L4_CONNECTED) k_sem_give(run); } int main(int argc, char *argv[]) { struct net_mgmt_event_callback ncb; net_mgmt_init_event_callback(ncb, zeh, NET_EVENT_L4_CONNECTED); net_mgmt_add_event_callback(ncb); k_sem_take(run, K_FOREVER); ... }值得注意的细节mgmt_event参数的类型在 Zephyr 4.2 之后从uint32_t变为uint64_t源码中通过ZEPHYR_VERSION_CODE 0x40200做了条件编译保证了示例同时兼容 4.2 之前与之后的 Zephyr 版本。这是移植到新版本 Zephyr 时容易踩的坑示例给出了官方推荐写法。2.2 连接超时与事件回调Mongoose 是事件驱动的连接、收包、出错都通过事件回调通知应用。示例的回调fn()覆盖了完整生命周期static const char *s_url https://example.org/; static const char *s_post_data NULL; // POST data static const int64_t s_timeout_ms 1500; // Connect timeout in milliseconds struct mg_mgr s_mgr; static int s_connected 0; static bool done false; static void fn(struct mg_connection *c, int ev, void *ev_data) { if (ev MG_EV_OPEN) { // Connection created. Store connect expiration time in c-data *(int64_t *) c-data mg_millis() s_timeout_ms; } else if (ev MG_EV_POLL) { if (mg_millis() *(int64_t *) c-data (c-is_connecting || c-is_resolving)) { mg_error(c, Connect timeout); } } else if (ev MG_EV_CONNECT) { struct mg_str host mg_url_host(s_url); if (c-is_tls) { struct mg_tls_opts opts {.ca s_ca, .name host}; mg_tls_init(c, opts); } int content_length s_post_data ? strlen(s_post_data) : 0; mg_printf(c, %s %s HTTP/1.0\r\n Host: %.*s\r\n Content-Type: octet-stream\r\n Content-Length: %d\r\n \r\n, s_post_data ? POST : GET, mg_url_uri(s_url), (int) host.len, host.buf, content_length); mg_send(c, s_post_data, content_length); } else if (ev MG_EV_HTTP_MSG) { struct mg_http_message *hm (struct mg_http_message *) ev_data; MG_INFO((%.*s, (int) hm-message.len, hm-message.buf)); c-is_draining 1; // Tell mongoose to close this connection *(bool *) c-fn_data true; // Tell event loop to stop } else if (ev MG_EV_ERROR) { *(bool *) c-fn_data true; // Error, tell event loop to stop } }各事件含义与对应处理事件触发时机示例中的处理MG_EV_OPEN连接对象创建记录超时截止时刻mg_millis() s_timeout_ms到c-dataMG_EV_POLL每次事件循环轮询检查是否仍处于连接/解析状态且已超时超时则调用mg_error()报错MG_EV_CONNECTTCP 连接建立若是 HTTPSc-is_tls用mg_tls_init()配置 CA 与 SNI 主机名随后组装并发送 HTTP 请求头与请求体MG_EV_HTTP_MSG收到完整 HTTP 响应打印整个响应消息设置is_draining关闭连接并把done置为true通知事件循环退出MG_EV_ERROR任何错误含超时直接置done true结束程序这里演示了 Mongoose 的两个常用技巧连接超时Mongoose 本身不强制超时示例把超时时刻存在c-data中在MG_EV_POLL里自行判断is_connecting || is_resolving是否超时。这种方式不依赖具体套接字实现在 Zephyr 这类嵌入式 RTOS 上同样有效。手动构造请求示例直接用mg_printf()拼接GET/POST请求行与头部并通过mg_send()发送请求体展示了 HTTP 协议层最底层的用法生产代码也可以改用mg_http_request()等封装函数定义见 src/http.h。2.3 主循环SNTP 校时 发起 HTTPS 请求uint64_t sntp_timer 0; while (!done) { uint64_t period mg_boot_timestamp_ms 0 ? 1000 : 24 * 3600 * 1000; if (mg_timer_expired(sntp_timer, period, mg_millis())) { mg_sntp_connect(s_mgr, NULL, NULL, NULL); } // Initiate the HTTPS request once we have a valid time (needed for TLS) if (mg_boot_timestamp_ms 0 !s_connected) { MG_INFO((Connecting to : [%s], s_url)); mg_http_connect(s_mgr, s_url, fn, done); s_connected 1; } mg_mgr_poll(s_mgr, 1000); } mg_mgr_free(s_mgr);这段代码体现了 HTTPS 客户端的必要前提TLS 证书有效期校验依赖可信的系统时间。流程如下只要mg_boot_timestamp_ms仍为 0系统时间未知就每隔 1 秒通过mg_sntp_connect()发起一次 SNTP 校时mg_sntp_connect实现在 src/sntp.c一旦时间有效mg_boot_timestamp_ms 0就调用mg_http_connect(s_mgr, s_url, fn, done)声明见 src/http.h实现在 src/http.c发起 HTTPS 连接并只发起一次s_connected标志防重入mg_mgr_poll(s_mgr, 1000)驱动事件循环1000ms 为单次轮询超时收到响应或出错后done为true循环退出mg_mgr_free()释放全部资源。2.4 内嵌 CA 根证书HTTPS 校验所需的 CA 根证书以 C 字符串形式直接内嵌在 src/certs.h 中包含 DigiCert High Assurance EV Root CA 与 DigiCert Global Root CA 两份根证书DER 编码的 PEM 文本。example.org的证书链由 DigiCert 签发因此这两份根证书足够完成其证书链校验。实际项目中应替换为目标服务器所用 CA 的根证书。2.5 Mongoose 平台与 TLS 后端配置tutorials/zephyr/http-client/src/mongoose_config.h 只有两行却决定了编译进固件的两个关键选型#define MG_ARCH MG_ARCH_ZEPHYR // 使用 Zephyr 平台抽象层对应 src/arch_zephyr.h #define MG_TLS MG_TLS_MBED // TLS 后端选用 mbedTLSMG_ARCH_ZEPHYR让 Mongoose 的计时、随机数、打印等底层接口映射到 Zephyr 内核 APIMG_TLS_MBED使 TLS 走 mbedTLS对应 src/tls_mbed.c这与prj.conf中开启的CONFIG_MBEDTLS_*系列配置一一对应。三、Zephyr 网络与 TLS 配置逐项解读prj.confprj.conf 是 Zephyr 侧的 Kconfig 配置分为四组3.1 网络协议栈CONFIG_NETWORKINGy CONFIG_NET_IPV4y CONFIG_NET_IPV6y CONFIG_NET_TCPy CONFIG_NET_UDPy CONFIG_NET_DHCPV4y CONFIG_NET_SOCKETSy CONFIG_NET_SOCKETS_POLL_MAX16 CONFIG_POSIX_APIy CONFIG_ZVFS_OPEN_MAX32 CONFIG_NET_CONFIG_SETTINGSy CONFIG_NET_CONNECTION_MANAGERy CONFIG_NET_LOGyCONFIG_NETWORKING打开 Zephyr 网络子系统CONFIG_NET_IPV4/CONFIG_NET_IPV6同时启用双栈CONFIG_NET_TCP/CONFIG_NET_UDP启用 TCP 与 UDP 传输层HTTP 走 TCP、SNTP 走 UDP。CONFIG_NET_DHCPV4使网卡通过 DHCP 自动获取 IPv4 地址这是示例能等来NET_EVENT_L4_CONNECTED事件的前提。CONFIG_NET_SOCKETS与CONFIG_POSIX_API提供 POSIX 风格套接字接口CONFIG_NET_SOCKETS_POLL_MAX16与CONFIG_ZVFS_OPEN_MAX32抬高了并发套接字/文件描述符上限为 Mongoose 管理多条连接留出余量。CONFIG_NET_CONNECTION_MANAGER启用连接管理器负责生成 L4 连接事件CONFIG_NET_LOG输出网络栈日志便于排查。3.2 任务栈与内存CONFIG_LOGy CONFIG_ISR_STACK_SIZE2048 CONFIG_MAIN_STACK_SIZE8192 CONFIG_IDLE_STACK_SIZE1024CONFIG_MAIN_STACK_SIZE8192是主线程栈大小——事件循环、TLS 握手与 HTTP 解析都在 main 线程中执行栈必须足够大。实际工程中若栈溢出常见于 TLS 首次握手应首先考虑加大此值。3.3 mbedTLS 配置CONFIG_MBEDTLSy CONFIG_MBEDTLS_SSL_MAX_CONTENT_LEN4096 CONFIG_MBEDTLS_PEM_CERTIFICATE_FORMATy CONFIG_MBEDTLS_ECDH_Cy CONFIG_MBEDTLS_ECDSA_Cy CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLEDy CONFIG_MBEDTLS_ECP_Cy CONFIG_MBEDTLS_ECP_ALL_ENABLEDy CONFIG_MBEDTLS_TLS_VERSION_1_2yCONFIG_MBEDTLS_SSL_MAX_CONTENT_LEN4096限制 TLS 单条记录最大长度在嵌入式场景下可显著节省内存默认 16KBCONFIG_MBEDTLS_PEM_CERTIFICATE_FORMAT使 mbedTLS 能解析certs.h中的 PEM 格式根证书ECDH/ECDSA/ECP系列配置启用椭圆曲线密钥交换与签名支持ECDHE-ECDSA是现代 TLS 服务端最常见的套件CONFIG_MBEDTLS_TLS_VERSION_1_2固定使用 TLS 1.2。3.4 最小化 C 库与调试CONFIG_MINIMAL_LIBCy CONFIG_MINIMAL_LIBC_RANDy CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE131072 CONFIG_PRINTKy CONFIG_MBEDTLS_DEBUGy CONFIG_MBEDTLS_LOG_LEVEL_DBGyCONFIG_MINIMAL_LIBC使用 Zephyr 精简 libc 以减小固件体积CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE131072128KB为堆分配器预留内存——Mongoose 的缓冲区、TLS 上下文等都从这里分配。CONFIG_MBEDTLS_DEBUG与CONFIG_MBEDTLS_LOG_LEVEL_DBG打开 mbedTLS 调试日志排查握手失败时非常有用量产固件可关闭以减小体积。四、QEMU 模拟无实体板卡的构建与运行原文档的核心亮点是用 Docker QEMU 模拟 x86 目标板让没有硬件的人也能完整体验 Zephyr Mongoose 开发流程。整套逻辑由 tutorials/zephyr/Makefile 与 tutorials/zephyr/http-client/Makefile 实现。4.1 前置条件主机安装Docker主机存在可用的TUN/TAP 网络接口默认名为tap0供 QEMU 模拟出的以太网卡接入宿主网络。Linux 下创建与配置 tap0 需要 root 权限具体网络配置方式参考仓库中 mip-tap 相关说明Makefile中亦通过--cap-addNET_ADMIN --device /dev/net/tun授予容器建 TAP 的能力。4.2 首次拉取 Zephyr 工程进入 tutorials/zephyr 目录执行make zephyr该目标会在tutorials/zephyr/zephyrproject/下通过west init初始化 Zephyr 工作区并执行west update拉取依赖含 Zephyr 内核、mbedTLS、相关 HAL。注意Makefile中针对 Zephyr v3.7 分支与其他版本执行了不同的minify规则用于裁剪west.yml中不需要的 HAL 与 CMSIS 项目以加速构建——这说明示例已验证过多个 Zephyr 版本。4.3 构建 qemu_x86 模拟目标make build BUILD_ARGS-b qemu_x86 OVERLAY-DOVERLAY_CONFIGoverlay-e1000.conf参数拆解参数含义BUILD_ARGS-b qemu_x86选择 Zephyr 的qemu_x86模拟目标板OVERLAY-DOVERLAY_CONFIGoverlay-e1000.conf叠加使用网卡模拟配置覆盖层默认BUILD_ARGS-b nucleo_f746zg未指定时默认构建真实板卡 STM32F746 Nucleobuild目标会先把仓库根目录的mongoose.[ch]拷贝进src/cp $(TOP_DIR)/mongoose.[ch] src/再在zephyrprojectrtos/ciDocker 镜像内执行west build -p auto。4.4 网卡模拟配置 overlay-e1000.confoverlay-e1000.conf 内容如下CONFIG_NET_L2_ETHERNETy CONFIG_NET_QEMU_ETHERNETy CONFIG_ETH_QEMU_IFACE_NAMEtap0 CONFIG_PCIEy #CONFIG_ETHERNET_LOG_LEVEL_DBGyCONFIG_NET_QEMU_ETHERNET启用 Zephyr 自带的 QEMU 以太网驱动e1000 模拟网卡CONFIG_ETH_QEMU_IFACE_NAMEtap0指定虚拟网卡挂接的宿主 TAP 接口名默认是tap0如需换名直接修改本文件或另建配置文件后通过修改OVERLAY参数中的OVERLAY_CONFIG指向新文件CONFIG_PCIE是 e1000 驱动所需的 PCIe 总线支持被注释的CONFIG_ETHERNET_LOG_LEVEL_DBG提示了调试以太网驱动时的开启位置。4.5 运行模拟目标make runrun目标在 Docker 中执行west build -t run启动 QEMU。其默认 Docker 参数为run: DOCKER_ARGS ? --cap-addNET_ADMIN --device /dev/net/tun --nethost -it即授予容器 NET_ADMIN 权限、把宿主的/dev/net/tun设备共享进容器、使用宿主网络命名空间--nethost这样tap0才能被容器内 QEMU 使用、以交互模式运行。如果宿主环境不允许共享/dev/net/tun文档明确建议通过DOCKER_ARGS追加所需的 Docker 参数例如make run DOCKER_ARGS--cap-addNET_ADMIN --device /dev/net/tun --nethost -it --device-cgroup-rulec 10 200 rwm运行后即可在 QEMU 串口日志中依次看到网络接口初始化 → DHCP 获取 IP →Mongoose version : vX.Y.Z版本打印 → SNTP 校时 →Connecting to : [https://example.org/]→ HTTP 响应内容由MG_INFO打印随后程序退出。4.6 真实板卡构建、烧录与调试模拟之外Makefile 也完整支持真实硬件流程# 构建默认目标板nucleo_f746zg make build # 烧录默认 Docker 参数含 --privileged 与 USB 设备映射 make flash # 进入 GDB 调试 make debug默认BUILD_ARGS-b nucleo_f746zg对应 STM32F746 Nucleo 板实际使用其他板卡时以BUILD_ARGS-b board覆盖即可。flash/debug默认带--privileged -v /dev/bus/usb/:/dev/bus/usb -it将宿主 USB 总线映射进容器以访问调试器如 ST-Link。五、常见问题与排查建议结合源码与配置整理实践中高频问题及定位方向QEMU 里网络不通、拿不到 IP先确认宿主tap0已创建且配置正确容器需--nethost才能看到它再检查overlay-e1000.conf中CONFIG_ETH_QEMU_IFACE_NAME与实际 TAP 名是否一致开启被注释的CONFIG_ETHERNET_LOG_LEVEL_DBG观察驱动日志。TLS 握手失败 / 证书校验错误优先排查系统时间是否已同步——HTTPS 请求只有在mg_boot_timestamp_ms 0后才会发起可观察 SNTP 校时日志其次确认certs.h中的根证书与目标服务器证书链匹配开启CONFIG_MBEDTLS_DEBUG后可看到 mbedTLS 的详细握手日志。连接超时Connect timeout错误s_timeout_ms默认 1500ms在慢速网络或首次 DNS 解析较慢时可能过短可调大该值另外确认prj.conf中CONFIG_NET_SOCKETS_POLL_MAX/CONFIG_ZVFS_OPEN_MAX未被多连接场景耗尽。栈溢出 / 内存不足优先增大CONFIG_MAIN_STACK_SIZETLS 握手耗栈明显与CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE。/dev/net/tun无法共享按文档建议通过make run DOCKER_ARGS...自行传入适用的 Docker 设备参数。六、小结本文围绕 tutorials/zephyr/http-client 完整梳理了 Zephyr Mongoose HTTPS 客户端的实现与运行源码侧src/main.c演示了NET_EVENT_L4_CONNECTED同步等待、mg_http_connect()事件驱动请求、MG_EV_*生命周期管理、SNTP 校时前置条件与连接超时自实现mongoose_config.h指定MG_ARCH_ZEPHYRMG_TLS_MBED配置侧prj.conf覆盖双栈网络、DHCP、mbedTLSTLS 1.2 ECDHE-ECDSA PEM 证书与内存预算overlay-e1000.conf定义 QEMU 模拟网卡与tap0的绑定工程侧Makefile 提供make zephyr / build / run / flash / debug全套基于 Docker 的流程默认qemu_x86模拟目标让开发者在无硬件条件下即可完整验证 HTTPS 客户端行为同一套流程可直接切换到nucleo_f746zg等真实板卡。这套Docker 拉取 Zephyr 工具链 QEMU 模拟 TAP 虚拟网卡的方法论对 tutorials/zephyr 目录下的全部示例HTTP 服务器、WebSocket、MQTT 等同样适用可作为 Zephyr 网络应用开发的通用起点。赞分享嵌入式网络通信物联网【免费下载链接】mongooseEmbedded web server, with TCP/IP network stack, MQTT and Websocket项目地址https://gitcode.com/gh_mirrors/mon/mongoose点击查看免费下载相关推荐Zephyr 中基于 Espressif QEMU 的无硬件开发DevKitC 板卡配置、镜像构建与调试指南Zephyr 中基于 Espressif QEMU 的无硬件开发DevKitC 板卡配置、镜像构建与调试指南 Espressif QEMU 是乐鑫维护的 QE操作系统嵌入式RTOS物联网QEMU STM32嵌入式开发者的虚拟硬件实验室QEMU STM32嵌入式开发者的虚拟硬件实验室 QEMU STM32 是一个基于开源 QEMU 项目的 STM32 微控制器仿真器为嵌入式开发者提供了一个嵌入式硬件仿真虚拟化Zephyr 中基于 BabbleSim 的 nRF54LM20 模拟板卡 nrf54lm20bsim 使用指南Zephyr 中基于 BabbleSim 的 nRF54LM20 模拟板卡 nrf54lm20bsim 使用指南 导读 nrf54lm20bsim 是 Zeph操作系统嵌入式RTOS物联网创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表