# API-libcomm — 通讯抽象层模块 > 版本: v1.0 > 日期: 2026-07-08 > 状态: 已实现(TCP/UDP 完整, UART 待实现) --- ## 1. 模块概述 libcomm 是 RTU 通讯装置的**通讯抽象层**,为上层协议栈(Modbus、IEC104 等)提供统一的 TCP/UDP/UART 通讯接口。 ### 设计思想 - **类型统一**:同一套 API 操作 TCP 服务器/客户端、UDP、UART - **异步事件驱动**:基于 epoll 单线程事件循环,非阻塞 I/O - **回调解耦**:接收数据和状态变化通过回调通知上层 - **纯 C 接口**:`extern "C"` 包裹,C/C++ 均可调用 ### 架构 ``` ┌──────────────────────────────────────────────┐ │ 协议层(libmodbus / lib60870) │ │ 调用 comm_create / comm_send / recv_cb │ ├──────────────────────────────────────────────┤ │ libcomm(纯 C 接口层) │ │ ┌──────────┬──────────┬──────────────────┐ │ │ │ TCP 服务 │ TCP 客户 │ UDP 服务 / 客户 │ │ │ │ 器端 │ 端 │ │ │ │ └──────────┴──────────┴──────────────────┘ │ │ ┌──────────────────────────────────────────┐ │ │ │ epoll 事件循环 + fd 管理 + 状态机 │ │ │ └──────────────────────────────────────────┘ │ ├──────────────────────────────────────────────┤ │ 实现层(C++: map/mutex + POSIX socket) │ └──────────────────────────────────────────────┘ ``` ### 源文件结构 ``` libcomm/ ├── inc/ │ └── myComm.h # 对外 C 接口头文件 └── src/ ├── comm_internal.h # 内部共享类型/全局变量/函数声明 ├── comm_core.cpp # 核心: create/destroy/run/stop + epoll 事件循环 ├── comm_tcp.cpp # TCP 服务器/客户端 ├── comm_udp.cpp # UDP 通讯 └── comm_uart.cpp # UART 串口通讯 ``` --- ## 2. 数据结构 ### 2.1 通讯类型 ```c typedef enum { COMM_TYPE_TCP_SERVER = 0, /** TCP 服务器(监听+accept) */ COMM_TYPE_TCP_CLIENT, /** TCP 客户端 */ COMM_TYPE_UDP_SERVER, /** UDP 服务器 */ COMM_TYPE_UDP_CLIENT, /** UDP 客户端 */ COMM_TYPE_UART /** UART 串口 */ } enum_comm_type; ``` ### 2.2 通讯状态 ```c typedef enum { COMM_STATE_DISCONNECTED = 0, /** 未连接 */ COMM_STATE_CONNECTING, /** 连接中 */ COMM_STATE_CONNECTED, /** 已连接 */ COMM_STATE_ERROR /** 错误状态 */ } enum_comm_state; ``` ### 2.3 参数结构体 ```c /** TCP 参数 */ typedef struct { char local_ip[64]; /** 本地 IP(服务器用) */ int local_port; /** 本地端口(服务器用) */ char remote_ip[64]; /** 远端 IP(客户端用) */ int remote_port; /** 远端端口(客户端用) */ } stru_tcp_para; /** UDP 参数 */ typedef struct { char local_ip[64]; /** 本地 IP */ int local_port; /** 本地端口 */ char remote_ip[64]; /** 远端 IP(客户端用) */ int remote_port; /** 远端端口(客户端用) */ } stru_udp_para; /** UART 参数 */ typedef struct { char device[128]; /** 串口设备路径(如 /dev/ttyS0) */ int baudrate; /** 波特率 */ int data_bits; /** 数据位(5/6/7/8) */ int stop_bits; /** 停止位(1/2) */ char parity; /** 校验位('N'/'E'/'O') */ } stru_uart_para; /** 通讯参数联合体 */ typedef union { stru_tcp_para tcp; stru_udp_para udp; stru_uart_para uart; } union_comm_para; ``` ### 2.4 回调函数类型 ```c /** 接收数据回调 */ typedef void (*comm_recv_cb)(int id, int fd, const unsigned char *data, int len); /** 状态变化回调 */ typedef void (*comm_state_cb)(int id, int fd, int state); ``` ### 2.5 错误码 | 常量 | 值 | 说明 | |------|-----|------| | `COMM_OK` | 0 | 成功 | | `COMM_ERR_PARAM` | -1 | 参数错误 | | `COMM_ERR_MEM` | -2 | 内存不足 | | `COMM_ERR_SOCKET` | -3 | Socket 创建失败 | | `COMM_ERR_BIND` | -4 | 绑定失败 | | `COMM_ERR_LISTEN` | -5 | 监听失败 | | `COMM_ERR_CONNECT` | -6 | 连接失败 | | `COMM_ERR_SEND` | -7 | 发送失败 | | `COMM_ERR_NOT_FOUND` | -8 | 实例不存在 | | `COMM_ERR_STATE` | -9 | 状态错误 | | `COMM_ERR_INTERNAL` | -10 | 内部错误 | --- ## 3. 接口函数 ### 3.1 comm_create — 创建通讯实例 ```c int comm_create(int type, int debug, const union_comm_para *para); ``` **参数**: - `type`:通讯类型(enum_comm_type) - `debug`:是否打印调试信息(1=打印, 0=静默) - `para`:通讯参数(根据 type 选择对应成员) **返回值**:`>=0` 实例 ID,`<0` 错误码 **使用场景**:协议栈初始化时创建对应的通讯通道 --- ### 3.2 comm_connect — 建立连接 ```c int comm_connect(int id); ``` **行为**(按类型): - TCP 服务器:bind + listen,注册到 epoll - TCP 客户端:非阻塞 connect,监听 EPOLLOUT 等待完成 - UDP:bind 本地端口 - UART:open 串口设备 + 配置波特率/数据位/停止位/校验 **返回值**:`COMM_OK` 成功,`<0` 错误码 --- ### 3.3 comm_disconnect — 断开连接 ```c int comm_disconnect(int id); ``` 关闭所有 fd(监听 + 客户端 + 本地),保留参数可重新 connect。 --- ### 3.4 comm_send — 发送数据 ```c int comm_send(int id, int fd, const unsigned char *data, int len); ``` **参数**: - `fd`:目标 fd(TCP 服务器需指定客户端 fd) - `data`/`len`:数据与长度 **返回值**:`>=0` 实际发送字节数,`<0` 错误码 **注意**:UDP 客户端会自动 sendto 到创建时指定的远端地址 --- ### 3.5 comm_recv_register — 注册接收回调 ```c int comm_recv_register(int id, comm_recv_cb cb); ``` epoll 检测到可读后,自动调用此回调,传入 `(id, fd, data, len)`。 --- ### 3.6 comm_state_register — 注册状态回调 ```c int comm_state_register(int id, comm_state_cb cb); ``` 连接建立/断开/错误时回调,传入 `(id, fd, state)`。 --- ### 3.7 comm_destroy — 销毁实例 ```c int comm_destroy(int id); ``` 关闭所有 fd、释放内存。 --- ### 3.8 comm_run / comm_stop — 事件循环 ```c int comm_run(void); /** 阻塞运行 epoll 事件循环 */ void comm_stop(void); /** 停止事件循环 */ ``` **约定**:调用者在独立线程中调用 `comm_run()`。停止时调用 `comm_stop()`。 --- ## 4. 使用示例 ### 4.1 TCP 客户端 ```c #include "myComm.h" static void on_recv(int id, int fd, const unsigned char *data, int len) { printf("recv %d bytes on fd=%d\n", len, fd); } static void on_state(int id, int fd, int state) { if (state == COMM_STATE_CONNECTED) { printf("connected!\n"); } } void tcp_client_example(void) { union_comm_para para; strcpy(para.tcp.remote_ip, "192.168.1.100"); para.tcp.remote_port = 502; para.tcp.local_ip[0] = '\0'; para.tcp.local_port = 0; int id = comm_create(COMM_TYPE_TCP_CLIENT, 1, ¶); comm_recv_register(id, on_recv); comm_state_register(id, on_state); comm_connect(id); /* 在另一个线程启动事件循环 */ comm_run(); } ``` ### 4.2 TCP 服务器 ```c void tcp_server_example(void) { union_comm_para para; strcpy(para.tcp.local_ip, "0.0.0.0"); para.tcp.local_port = 502; int id = comm_create(COMM_TYPE_TCP_SERVER, 1, ¶); comm_recv_register(id, on_recv); comm_state_register(id, on_state); comm_connect(id); comm_run(); } ``` ### 4.3 UDP ```c void udp_example(void) { union_comm_para para; strcpy(para.udp.local_ip, "0.0.0.0"); para.udp.local_port = 2404; int id = comm_create(COMM_TYPE_UDP_SERVER, 1, ¶); comm_recv_register(id, on_recv); comm_connect(id); comm_run(); } ``` --- ## 5. 依赖关系 ``` myBase.h → libcomm (无其他模块依赖) ``` libcomm 是阶段 2 的第一个模块,被后续 `libmodbus`、`lib60870` 等协议栈依赖。 --- ## 6. 程序运行流程 ``` comm_create(type, para) → 分配 stru_comm_instance,拷贝参数,返回 id → 首次调用时初始化 epoll + eventfd comm_connect(id) → TCP_SERVER: socket → bind → listen → epoll_add(listen_fd) → TCP_CLIENT: socket → nonblock-connect → epoll_add(fd, EPOLLOUT) → UDP: socket → bind → epoll_add(fd) → UART: open(device) → tcsetattr → epoll_add(fd) comm_run() [阻塞,需在独立线程中调用] → epoll_wait 循环 → EPOLLIN (listen_fd) → accept → epoll_add(client_fd) → state_cb → EPOLLIN (data_fd) → recv → recv_cb → EPOLLOUT → getsockopt(SO_ERROR) → connect 完成 → state_cb → EPOLLERR/HUP/RDHUP → close_fd → state_cb(DISCONNECTED) comm_stop() → write(eventfd) → epoll 收到 → g_running = false → 退出循环 ```