370 lines
11 KiB
Markdown
370 lines
11 KiB
Markdown
# 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 — 事件管理器
|
||
|
||
```c
|
||
struct mg_mgr
|
||
{
|
||
struct mg_connection *conns; /* 活动连接链表 */
|
||
struct mg_timer *timers; /* 定时器链表 */
|
||
// ... 内部字段
|
||
};
|
||
```
|
||
|
||
每个进程只需一个 `mg_mgr` 实例,管理所有连接和定时器。
|
||
|
||
### 4.2 mg_connection — 连接
|
||
|
||
```c
|
||
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 事件类型
|
||
|
||
```c
|
||
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 生命周期
|
||
|
||
```c
|
||
/** 初始化事件管理器 */
|
||
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);
|
||
```
|
||
|
||
**典型用法**:
|
||
```c
|
||
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 服务器
|
||
|
||
```c
|
||
/** 创建 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 示例**:
|
||
```c
|
||
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
|
||
|
||
```c
|
||
/** 升级 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)**:
|
||
```c
|
||
#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 服务端示例**:
|
||
```c
|
||
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 定时器
|
||
|
||
```c
|
||
/** 添加一次性定时器 */
|
||
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 通用收发
|
||
|
||
```c
|
||
/** 发送原始数据 */
|
||
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. 编译与构建
|
||
|
||
```bash
|
||
# 编译 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` 头部注释。
|
||
|
||
---
|
||
|
||
## 10. 参考链接
|
||
|
||
- [Mongoose 官方文档](https://mongoose.ws/documentation/)
|
||
- [Mongoose GitHub](https://github.com/cesanta/mongoose)
|
||
- [WebSocket RFC 6455](https://datatracker.ietf.org/doc/html/rfc6455)
|
||
- [HTTP/1.1 RFC 7230](https://datatracker.ietf.org/doc/html/rfc7230)
|