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

11 KiB
Raw Blame History

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 — 事件管理器

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->bodyhm->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 头部注释。


10. 参考链接