# IPC 模块 ## 概述 IPC(Inter-Process Communication)模块提供进程间通讯功能,支持 Windows Named Pipe 和 Linux Unix Domain Socket。 **⚠️ 重要提示:** IPC 模块 **不支持 macOS** 平台。如需跨平台进程间通讯方案,请考虑使用 TCP/IP 替代方案。 --- ## 平台支持 | 平台 | 实现方式 | 状态 | 说明 | |------|----------|------|------| | Windows | Named Pipe | ✅ 完全支持 | 使用 `\\.\pipe\` 格式路径 | | Linux | Unix Domain Socket | ✅ 完全支持 | 使用文件系统路径,如 `/tmp/netleaf_ipc` | | macOS | 不支持 | ❌ 无实现 | 该模块在 macOS 上不可用 | ### macOS 平台限制说明 IPC 模块在 macOS 上 **不提供任何功能**: - 所有 API 调用将返回错误码 `-1` - `nl_ipc_is_available()` 返回 `0`(不可用) - 模块初始化函数 `nl_ipc_init()` 将返回错误 - 建议在使用前通过 `nl_ipc_is_available()` 检查平台支持 --- ## API 参考 ### 平台检测 ```c // 检查IPC模块是否在当前平台可用 int nl_ipc_is_available(void); // 初始化IPC模块 int nl_ipc_init(void); // 关闭IPC模块 void nl_ipc_shutdown(void); ``` ### 服务端 API ```c // 创建IPC服务器 // path: Windows 使用 "\\\\.\\pipe\\",Linux 使用文件路径如 "/tmp/netleaf_ipc" nl_ipc_server_t* nl_ipc_server_create(const char* path); // 启动IPC服务器(非阻塞) int nl_ipc_server_start(nl_ipc_server_t* server); // 停止IPC服务器 void nl_ipc_server_stop(nl_ipc_server_t* server); // 销毁IPC服务器 void nl_ipc_server_destroy(nl_ipc_server_t* server); // 设置数据回调 void nl_ipc_server_set_data_callback(nl_ipc_server_t* server, void (*callback)(nl_ipc_client_t* client, const char* data, size_t len, void* user_data), void* user_data); // 设置客户端连接回调 void nl_ipc_server_set_connect_callback(nl_ipc_server_t* server, void (*callback)(nl_ipc_client_t* client, void* user_data), void* user_data); // 设置客户端断开回调 void nl_ipc_server_set_disconnect_callback(nl_ipc_server_t* server, void (*callback)(nl_ipc_client_t* client, void* user_data), void* user_data); // 向指定客户端发送数据 int nl_ipc_server_send_to(nl_ipc_server_t* server, nl_ipc_client_t* client, const char* data, size_t len); // 向所有客户端广播数据 int nl_ipc_server_broadcast(nl_ipc_server_t* server, const char* data, size_t len); // 获取连接的客户端数量 int nl_ipc_server_get_client_count(nl_ipc_server_t* server); ``` ### 客户端 API ```c // 创建IPC客户端 nl_ipc_client_t* nl_ipc_client_create(const char* path); // 连接到IPC服务器(阻塞调用,超时时间为5秒) int nl_ipc_client_connect(nl_ipc_client_t* client); // 带超时的连接(单位:毫秒) int nl_ipc_client_connect_with_timeout(nl_ipc_client_t* client, int timeout_ms); // 断开连接 void nl_ipc_client_disconnect(nl_ipc_client_t* client); // 销毁IPC客户端 void nl_ipc_client_destroy(nl_ipc_client_t* client); // 发送数据(阻塞) int nl_ipc_client_send(nl_ipc_client_t* client, const char* data, size_t len); // 设置数据回调 void nl_ipc_client_set_data_callback(nl_ipc_client_t* client, void (*callback)(const char* data, size_t len, void* user_data), void* user_data); // 设置连接状态回调 void nl_ipc_client_set_status_callback(nl_ipc_client_t* client, void (*callback)(int connected, void* user_data), void* user_data); // 检查连接状态 int nl_ipc_client_is_connected(nl_ipc_client_t* client); ``` --- ## 使用示例 ### 示例 1:简单的服务端 ```c #include "netleaf_ipc.h" #include void on_client_connect(nl_ipc_client_t* client, void* user_data) { printf("Client connected\n"); } void on_client_disconnect(nl_ipc_client_t* client, void* user_data) { printf("Client disconnected\n"); } void on_data_received(nl_ipc_client_t* client, const char* data, size_t len, void* user_data) { nl_ipc_server_t* server = (nl_ipc_server_t*)user_data; printf("Received: %.*s\n", (int)len, data); // 回显数据给客户端 nl_ipc_server_send_to(server, client, data, len); // 广播给所有客户端 nl_ipc_server_broadcast(server, data, len); } int main() { // 检查平台支持 if (!nl_ipc_is_available()) { printf("IPC module is not available on this platform\n"); return 1; } // 初始化模块 if (nl_ipc_init() != 0) { printf("Failed to initialize IPC module\n"); return 1; } #ifdef _WIN32 const char* pipe_path = "\\\\.\\pipe\\netleaf_example"; #else const char* pipe_path = "/tmp/netleaf_example"; #endif // 创建服务器 nl_ipc_server_t* server = nl_ipc_server_create(pipe_path); if (!server) { printf("Failed to create IPC server\n"); nl_ipc_shutdown(); return 1; } // 设置回调 nl_ipc_server_set_connect_callback(server, on_client_connect, NULL); nl_ipc_server_set_disconnect_callback(server, on_client_disconnect, NULL); nl_ipc_server_set_data_callback(server, on_data_received, server); // 启动服务器 if (nl_ipc_server_start(server) != 0) { printf("Failed to start IPC server\n"); nl_ipc_server_destroy(server); nl_ipc_shutdown(); return 1; } printf("IPC server started on: %s\n", pipe_path); // 保持运行 while (1) { #ifdef _WIN32 Sleep(1000); #else sleep(1); #endif } // 清理 nl_ipc_server_stop(server); nl_ipc_server_destroy(server); nl_ipc_shutdown(); return 0; } ``` ### 示例 2:简单的客户端 ```c #include "netleaf_ipc.h" #include #include void on_data_received(const char* data, size_t len, void* user_data) { printf("Server response: %.*s\n", (int)len, data); } void on_status_changed(int connected, void* user_data) { printf("Connection status: %s\n", connected ? "connected" : "disconnected"); } int main() { // 检查平台支持 if (!nl_ipc_is_available()) { printf("IPC module is not available on this platform\n"); return 1; } // 初始化模块 if (nl_ipc_init() != 0) { printf("Failed to initialize IPC module\n"); return 1; } #ifdef _WIN32 const char* pipe_path = "\\\\.\\pipe\\netleaf_example"; #else const char* pipe_path = "/tmp/netleaf_example"; #endif // 创建客户端 nl_ipc_client_t* client = nl_ipc_client_create(pipe_path); if (!client) { printf("Failed to create IPC client\n"); nl_ipc_shutdown(); return 1; } // 设置回调 nl_ipc_client_set_data_callback(client, on_data_received, NULL); nl_ipc_client_set_status_callback(client, on_status_changed, NULL); // 连接到服务器(带超时) printf("Connecting to %s...\n", pipe_path); int result = nl_ipc_client_connect_with_timeout(client, 3000); if (result != 0) { printf("Failed to connect to server\n"); nl_ipc_client_destroy(client); nl_ipc_shutdown(); return 1; } printf("Connected successfully\n"); // 发送数据 const char* message = "Hello from client!"; nl_ipc_client_send(client, message, strlen(message)); // 保持连接 while (1) { #ifdef _WIN32 Sleep(1000); #else sleep(1); #endif } // 清理 nl_ipc_client_disconnect(client); nl_ipc_client_destroy(client); nl_ipc_shutdown(); return 0; } ``` ### 示例 3:错误处理与平台检测 ```c #include "netleaf_ipc.h" #include int main() { // === 平台检测 === if (!nl_ipc_is_available()) { printf("ERROR: IPC module is not available on this platform!\n"); printf("Supported platforms: Windows, Linux\n"); printf("Unsupported: macOS\n"); return 1; } // === 初始化 === int init_result = nl_ipc_init(); if (init_result != 0) { printf("ERROR: Failed to initialize IPC module (code: %d)\n", init_result); return 1; } // === 创建服务器 === #ifdef _WIN32 const char* path = "\\\\.\\pipe\\my_app"; #else const char* path = "/tmp/my_app_ipc"; #endif nl_ipc_server_t* server = nl_ipc_server_create(path); if (!server) { printf("ERROR: Failed to create IPC server\n"); nl_ipc_shutdown(); return 1; } // === 启动服务器 === int start_result = nl_ipc_server_start(server); if (start_result != 0) { printf("ERROR: Failed to start IPC server (code: %d)\n", start_result); nl_ipc_server_destroy(server); nl_ipc_shutdown(); return 1; } printf("IPC server started successfully on: %s\n", path); // ... 业务逻辑 ... // === 清理 === nl_ipc_server_stop(server); nl_ipc_server_destroy(server); nl_ipc_shutdown(); return 0; } ``` --- ## 路径格式说明 ### Windows (Named Pipe) 路径格式:`\\.\pipe\` ```c // 正确格式 const char* path = "\\\\.\\pipe\\my_pipe_name"; // 命名规则: // - 管道名称不能包含反斜杠 // - 最大长度为 256 字符 // - 推荐使用字母、数字和下划线 ``` ### Linux (Unix Domain Socket) 路径格式:文件系统路径 ```c // 正确格式 const char* path = "/tmp/my_socket"; const char* path = "/var/run/my_app.sock"; // 注意事项: // - 路径必须指向可写目录 // - 需要适当的文件系统权限 // - 建议使用 /tmp 或 /var/run 目录 ``` --- ## 线程安全 IPC模块采用线程安全设计: | 特性 | 说明 | |------|------| | 互斥锁保护 | 内部使用互斥锁保护共享资源 | | 并发连接 | 支持多客户端并发连接 | | 回调线程 | 数据回调在独立线程中执行 | | 线程安全API | 所有公开API均可从多个线程调用 | --- ## 错误码 | 错误码 | 含义 | |--------|------| | `0` | 成功 | | `-1` | 通用错误 | | `-2` | 平台不支持 | | `-3` | 内存分配失败 | | `-4` | 无效参数 | | `-5` | 连接失败 | | `-6` | 发送失败 | | `-7` | 服务器未启动 | --- ## 模块信息 ```c NL_MODULE_INFO_BEGIN(ipc, NL_MODULE_TYPE_IPC) NL_MODULE_NAME("IPC") NL_MODULE_VERSION("2.2.1") NL_MODULE_DESCRIPTION("Inter-process communication (Windows Named Pipe / Linux Unix Domain Socket)") NL_MODULE_AUTHOR("508364") NL_MODULE_PLATFORM(WINDOWS, LINUX) NL_MODULE_CAPABILITY(NL_MODULE_CAP_IPC_SERVER) NL_MODULE_CAPABILITY(NL_MODULE_CAP_IPC_CLIENT) NL_MODULE_INFO_END() ``` --- ## 最佳实践 ### 1. 始终检查平台支持 ```c if (!nl_ipc_is_available()) { // 提供替代方案或优雅降级 printf("IPC not available, falling back to TCP\n"); } ``` ### 2. 使用 RAII 模式管理资源 ```c // 创建时立即初始化,销毁时自动清理 typedef struct { nl_ipc_server_t* server; } AppContext; AppContext* app_create() { AppContext* ctx = malloc(sizeof(AppContext)); ctx->server = nl_ipc_server_create("/tmp/my_app"); return ctx; } void app_destroy(AppContext* ctx) { if (ctx->server) { nl_ipc_server_stop(ctx->server); nl_ipc_server_destroy(ctx->server); } free(ctx); } ``` ### 3. 设置合理的超时时间 ```c // 避免无限等待 int result = nl_ipc_client_connect_with_timeout(client, 5000); // 5秒超时 ``` ### 4. 处理连接断开 ```c void on_status_changed(int connected, void* user_data) { if (!connected) { // 尝试重新连接或通知上层 printf("Disconnected, attempting reconnect...\n"); } } ``` ### 5. 注意路径长度限制 ```c // Windows Named Pipe 路径限制 // 最大路径长度:256 字符 // 管道名称最大长度:256 - 9 = 247 字符(减去 "\\\\.\\pipe\\") // Linux Unix Domain Socket 路径限制 // 最大路径长度:通常为 108 字符(依赖于系统) ``` --- ## 常见问题 ### Q: macOS 平台上如何使用进程间通讯? **A:** IPC 模块不支持 macOS。建议使用 TCP/IP socket 作为跨平台替代方案: ```c // 使用 TCP socket 实现跨平台进程间通讯 nl_server_t* server = nl_server_create(NL_PROTO_TCP, 12345); ``` ### Q: Windows 上管道名称有什么限制? **A:** - 最大长度:256 字符(包括 `\\.\pipe\` 前缀) - 不能包含反斜杠 - 推荐使用字母、数字和下划线 ### Q: Linux 上 Unix Socket 文件需要手动删除吗? **A:** 是的。服务器停止时会自动删除 socket 文件,但如果程序异常退出,可能需要手动清理: ```bash rm /tmp/netleaf_ipc ``` ### Q: 如何实现双向通讯? **A:** IPC 模块天然支持双向通讯。服务端和客户端都可以发送和接收数据: ```c // 服务端发送 nl_ipc_server_send_to(server, client, data, len); // 客户端发送 nl_ipc_client_send(client, data, len); ```