IPC - 508364/NetLeaf GitHub Wiki

IPC 模块

概述

IPC(Inter-Process Communication)模块提供进程间通讯功能,支持 Windows Named Pipe 和 Linux Unix Domain Socket。

⚠️ 重要提示: IPC 模块 不支持 macOS 平台。如需跨平台进程间通讯方案,请考虑使用 TCP/IP 替代方案。


平台支持

平台 实现方式 状态 说明
Windows Named Pipe ✅ 完全支持 使用 \\.\pipe\<name> 格式路径
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 参考

平台检测

// 检查IPC模块是否在当前平台可用
int nl_ipc_is_available(void);

// 初始化IPC模块
int nl_ipc_init(void);

// 关闭IPC模块
void nl_ipc_shutdown(void);

服务端 API

// 创建IPC服务器
// path: Windows 使用 "\\\\.\\pipe\\<name>",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

// 创建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:简单的服务端

#include "netleaf_ipc.h"
#include <stdio.h>

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:简单的客户端

#include "netleaf_ipc.h"
#include <stdio.h>
#include <string.h>

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:错误处理与平台检测

#include "netleaf_ipc.h"
#include <stdio.h>

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\<pipe_name>

// 正确格式
const char* path = "\\\\.\\pipe\\my_pipe_name";

// 命名规则:
// - 管道名称不能包含反斜杠
// - 最大长度为 256 字符
// - 推荐使用字母、数字和下划线

Linux (Unix Domain Socket)

路径格式:文件系统路径

// 正确格式
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 服务器未启动

模块信息

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. 始终检查平台支持

if (!nl_ipc_is_available()) {
    // 提供替代方案或优雅降级
    printf("IPC not available, falling back to TCP\n");
}

2. 使用 RAII 模式管理资源

// 创建时立即初始化,销毁时自动清理
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. 设置合理的超时时间

// 避免无限等待
int result = nl_ipc_client_connect_with_timeout(client, 5000); // 5秒超时

4. 处理连接断开

void on_status_changed(int connected, void* user_data) {
    if (!connected) {
        // 尝试重新连接或通知上层
        printf("Disconnected, attempting reconnect...\n");
    }
}

5. 注意路径长度限制

// Windows Named Pipe 路径限制
// 最大路径长度:256 字符
// 管道名称最大长度:256 - 9 = 247 字符(减去 "\\\\.\\pipe\\")

// Linux Unix Domain Socket 路径限制
// 最大路径长度:通常为 108 字符(依赖于系统)

常见问题

Q: macOS 平台上如何使用进程间通讯?

A: IPC 模块不支持 macOS。建议使用 TCP/IP socket 作为跨平台替代方案:

// 使用 TCP socket 实现跨平台进程间通讯
nl_server_t* server = nl_server_create(NL_PROTO_TCP, 12345);

Q: Windows 上管道名称有什么限制?

A:

  • 最大长度:256 字符(包括 \\.\pipe\ 前缀)
  • 不能包含反斜杠
  • 推荐使用字母、数字和下划线

Q: Linux 上 Unix Socket 文件需要手动删除吗?

A: 是的。服务器停止时会自动删除 socket 文件,但如果程序异常退出,可能需要手动清理:

rm /tmp/netleaf_ipc

Q: 如何实现双向通讯?

A: IPC 模块天然支持双向通讯。服务端和客户端都可以发送和接收数据:

// 服务端发送
nl_ipc_server_send_to(server, client, data, len);

// 客户端发送
nl_ipc_client_send(client, data, len);
⚠️ **GitHub.com Fallback** ⚠️