11 KiB
11 KiB
API-libmongoose — 嵌入式 HTTP/WebSocket 网络库
版本: v1.0
日期: 2026-07-08
来源: Mongoose v7.22 (MIT 许可,https://github.com/cesanta/mongoose)
状态: ✅ 导入完成,x86 + ARM 双平台编译通过(零警告)
1. 模块概述
libmongoose 是 Mongoose v7.22 开源库的封装模块。Mongoose 是一个单文件、纯 C 实现的嵌入式网络库,广泛用于 IoT 和嵌入式设备。本模块主要用于 RTU 的 Web 管理服务(libweb_server),提供 HTTP REST API 和 WebSocket 双向通信能力。
| 功能 | 说明 |
|---|---|
| HTTP 服务器 | 解析请求、路由匹配、JSON 响应,用于 REST API |
| WebSocket | 双向消息推送(实时遥测数据、告警通知) |
| 事件驱动 | 基于 epoll 的异步 IO,单线程管理所有连接 |
| 定时器 | 毫秒级软定时器,无需额外线程 |
| 跨平台 | Linux / FreeRTOS / Zephyr / ESP32 等,本工程只用 Linux |
架构位置
libweb_server (system/) — REST API + WebSocket 管理
│
▼
libmongoose (protocol/) — HTTP/WS 协议栈
│
▼
Linux kernel socket + epoll
2. 文件结构
src/protocol/libmongoose/
├── inc/
│ ├── myMongoose.h # RTU 适配头(编译配置宏 + #include "mongoose.h")
│ └── mongoose.h # Mongoose v7.22 头文件(5748 行,上游文件)
└── src/
└── mongoose.c # Mongoose v7.22 实现(31786 行,上游文件)
release/
├── inc/
│ ├── myMongoose.h # 拷贝自 src,供其他模块包含
│ └── mongoose.h # 拷贝自 src
└── x86/lib/
└── libmongoose.a # x86 编译产物(462KB)
└── arm/lib/
└── libmongoose.a # ARM 编译产物(471KB)
3. 编译配置
在 myMongoose.h 中定义以下宏(必须在 #include "mongoose.h" 之前):
| 宏 | 值 | 说明 |
|---|---|---|
MG_ENABLE_LOG |
1 | 启用内置日志(printf 到 stderr) |
MG_ENABLE_FILE |
0 | 禁用文件系统(RTU 不通过 mongoose 提供静态文件) |
MG_ENABLE_POSIX_FS |
0 | 禁用 POSIX 文件 API |
MG_ENABLE_EPOLL |
1 | 启用 epoll(Linux 高效 IO 多路复用) |
MG_ENABLE_POLL |
1 | 启用 poll(epoll 回退方案) |
MG_ENABLE_SOCKET |
1 | 使用 Linux 内核 socket |
4. 核心数据结构
4.1 mg_mgr — 事件管理器
struct mg_mgr
{
struct mg_connection *conns; /* 活动连接链表 */
struct mg_timer *timers; /* 定时器链表 */
// ... 内部字段
};
每个进程只需一个 mg_mgr 实例,管理所有连接和定时器。
4.2 mg_connection — 连接
struct mg_connection
{
struct mg_connection *next; /* 链表指针 */
struct mg_mgr *mgr; /* 所属管理器 */
struct mg_addr peer; /* 对端地址 */
void *fd; /* socket 文件描述符 */
unsigned long id; /* 连接 ID */
unsigned is_websocket : 1; /* 是否为 WebSocket 连接 */
unsigned is_client : 1; /* 是否为客户端连接 */
// ...
};
4.3 事件类型
enum
{
MG_EV_ERROR, /* 错误 */
MG_EV_OPEN, /* 连接建立(仅客户端出站连接) */
MG_EV_POLL, /* mg_mgr_poll() 每次迭代触发 */
MG_EV_RESOLVE, /* DNS 解析完成 */
MG_EV_CONNECT, /* TCP 连接完成 */
MG_EV_ACCEPT, /* TCP 新连接接受 */
MG_EV_TLS_HS, /* TLS 握手完成 */
MG_EV_READ, /* 数据可读 */
MG_EV_WRITE, /* 数据可写 */
MG_EV_CLOSE, /* 连接关闭 */
MG_EV_HTTP_MSG, /* HTTP 请求/响应解析完成 */
MG_EV_HTTP_CHUNK, /* HTTP 分块数据 */
MG_EV_WS_OPEN, /* WebSocket 握手完成 */
MG_EV_WS_MSG, /* WebSocket 消息到达 */
MG_EV_WS_CTL, /* WebSocket 控制帧 */
MG_EV_MQTT_CMD, /* MQTT 命令 */
MG_EV_MQTT_MSG, /* MQTT 消息 */
MG_EV_MQTT_OPEN, /* MQTT 连接建立 */
MG_EV_SNTP_TIME, /* SNTP 时间 */
MG_EV_USER, /* 用户自定义事件起点 */
};
5. 接口函数
5.1 生命周期
/** 初始化事件管理器 */
void mg_mgr_init(struct mg_mgr *mgr);
/** 事件循环(每次调用处理一批事件,阻塞不超过 ms 毫秒) */
void mg_mgr_poll(struct mg_mgr *mgr, int ms);
/** 销毁事件管理器(关闭所有连接,释放所有内存) */
void mg_mgr_free(struct mg_mgr *mgr);
典型用法:
struct mg_mgr mgr;
mg_mgr_init(&mgr);
/* 注册 HTTP/WS 监听 + 定时器 */
// ...
while (running)
{
mg_mgr_poll(&mgr, 50); /* 50ms 超时 */
}
mg_mgr_free(&mgr);
5.2 HTTP 服务器
/** 创建 HTTP 监听连接 */
struct mg_connection *mg_http_listen(struct mg_mgr *mgr, const char *url,
mg_event_handler_t fn, void *fn_data);
/** 获取 HTTP 请求/响应消息 */
int mg_http_get_request_len(const unsigned char *buf, size_t buf_len);
struct mg_http_message *mg_http_parse(const char *buf, size_t len);
struct mg_http_message *mg_http_parse2(const char *buf, size_t len);
/** 响应辅助 */
void mg_http_reply(struct mg_connection *c, int status_code,
const char *headers, const char *body_fmt, ...);
void mg_http_serve_dir(struct mg_connection *c, struct mg_http_message *hm,
const char *root);
/** 路由匹配 */
bool mg_match(struct mg_str str, struct mg_str pattern, struct mg_str *caps);
bool mg_http_match_uri(const struct mg_http_message *hm, const char *pattern);
REST API 示例:
static void fn(struct mg_connection *c, int ev, void *ev_data)
{
if (ev == MG_EV_HTTP_MSG)
{
struct mg_http_message *hm = (struct mg_http_message *)ev_data;
if (mg_http_match_uri(hm, "/api/status"))
{
mg_http_reply(c, 200, "Content-Type: application/json\r\n",
"{\"status\":\"ok\"}");
}
}
}
mg_http_listen(&mgr, "http://0.0.0.0:8080", fn, NULL);
5.3 WebSocket
/** 升级 HTTP 连接到 WebSocket */
void mg_ws_upgrade(struct mg_connection *c, struct mg_http_message *hm,
const char *fmt, ...);
/** 发送 WebSocket 消息 */
size_t mg_ws_send(struct mg_connection *c, const void *buf, size_t len, int op);
/** 格式化发送 WebSocket 消息 */
size_t mg_ws_printf(struct mg_connection *c, int op, const char *fmt, ...);
/** 封装非 WS socket 为 WS 帧(用于代理) */
size_t mg_ws_wrap(struct mg_connection *c, size_t len, int op,
const void *buf, size_t buf_len);
/** 主动连接 WebSocket 服务器(客户端模式) */
struct mg_connection *mg_ws_connect(struct mg_mgr *mgr, const char *url,
mg_event_handler_t fn, void *fn_data,
const char *fmt, ...);
WebSocket 帧操作码 (op):
#define WEBSOCKET_OP_CONTINUE 0 /* 继续帧 */
#define WEBSOCKET_OP_TEXT 1 /* 文本消息 */
#define WEBSOCKET_OP_BINARY 2 /* 二进制消息 */
#define WEBSOCKET_OP_CLOSE 8 /* 关闭握手 */
#define WEBSOCKET_OP_PING 9 /* Ping */
#define WEBSOCKET_OP_PONG 10 /* Pong */
WebSocket 服务端示例:
static void fn(struct mg_connection *c, int ev, void *ev_data)
{
if (ev == MG_EV_HTTP_MSG)
{
struct mg_http_message *hm = (struct mg_http_message *)ev_data;
if (mg_match(hm->uri, mg_str("/ws"), NULL))
{
mg_ws_upgrade(c, hm, NULL);
}
}
else if (ev == MG_EV_WS_MSG)
{
struct mg_ws_message *wm = (struct mg_ws_message *)ev_data;
/* 回显消息 */
mg_ws_send(c, wm->data.buf, wm->data.len, WEBSOCKET_OP_TEXT);
}
}
5.4 定时器
/** 添加一次性定时器 */
struct mg_timer *mg_timer_add(struct mg_mgr *mgr, uint64_t milliseconds,
unsigned flags, void (*fn)(void *), void *arg);
/** 定时器标志 */
#define MG_TIMER_REPEAT 1 /* 周期性定时器 */
#define MG_TIMER_RUN_NOW 2 /* 立即运行一次 */
5.5 通用收发
/** 发送原始数据 */
bool mg_send(struct mg_connection *c, const void *buf, size_t len);
/** 格式化发送 */
size_t mg_printf(struct mg_connection *c, const char *fmt, ...);
size_t mg_vprintf(struct mg_connection *c, const char *fmt, va_list *ap);
/** 关闭连接 */
void mg_close_conn(struct mg_connection *c);
6. 使用约束与注意事项
6.1 线程安全
mg_mgr_poll()必须在单线程中调用- 如需要多线程,通过
mg_wakeup()向事件循环投递消息
6.2 内存管理
- 所有通过
mg_http_listen()创建的连接在mg_mgr_free()时自动关闭释放 mg_http_message中的hm->body、hm->query等字段为协议栈内部缓冲区,不可手动 free
6.3 与 RTU 的集成方式
libweb_server作为 RTU 的独立线程模块,在线程内创建自己的mg_mgr- 通过 X-Macro 框架的定时器触发
mg_mgr_poll() - HTTP 路由中使用
dc_get_signal_val()获取实时数据,dc_set_out_signal_val()发布前端写入的数据
6.4 日志说明
mongoose 内部使用 printf 向 stderr 输出日志(MG_ENABLE_LOG=1)。在 RTU 装置上 stderr 通常重定向到 /dev/null 或 syslog。如需捕获 mongoose 日志,可定义 MG_ENABLE_CUSTOM_LOG=1 并提供自定义 MG_LOG() 宏。
7. 依赖关系
7.1 本模块依赖
- 无(mongoose 是纯 C、零依赖的单文件库,直接使用 Linux socket API)
7.2 依赖本模块的模块
| 模块 | 用途 |
|---|---|
libweb_server (system/) |
HTTP REST API + WebSocket 通信 |
7.3 模块依赖图
┌──────────────────┐
│ libweb_server │ (RTU 线程模块)
│ REST API + WS │
└────────┬─────────┘
│ myMongoose.h
▼
┌──────────────────┐
│ libmongoose │ (纯 C 协议栈)
│ HTTP + WebSocket │
└────────┬─────────┘
│
▼
Linux Socket API + epoll
8. 编译与构建
# 编译 libmongoose.a
cd release/src/protocol/libmongoose
make -f makefile all # x86
make -f makefile CROSS=arm all # ARM
# 参与全量构建
cd release && ./build.sh # x86
cd release && ./build.sh arm # ARM
9. 许可证
Mongoose 使用 MIT 许可证(商业友好)。完整许可文本见 mongoose.h 头部注释。