RTU_ALL_AI/docs/protocol/libmongoose/API-libmongoose.md

370 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 | 启用 epollLinux 高效 IO 多路复用) |
| `MG_ENABLE_POLL` | 1 | 启用 pollepoll 回退方案) |
| `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)