C++ 进程间通信IPC的实现示例

 更新时间:2025年06月13日 09:59:19   作者:北辰alk  
本文主要介绍了C++ 进程间通信IPC的实现示例,包括管道、消息队列、共享内存等基础与高级方法,具有一定的参考价值,感兴趣的可以了解一下

进程间通信(Inter-Process Communication, IPC)是操作系统提供的允许不同进程间交换数据和同步行为的机制。C++作为系统级编程语言,支持多种IPC方式。本文将详细介绍C++中常用的进程间通信技术。

1. 管道(Pipe)

1.1 匿名管道

匿名管道是Unix-like系统中最基础的IPC方式,具有以下特点:

  • 单向通信,半双工
  • 只能用于有亲缘关系的进程间通信
  • 基于字节流
#include <unistd.h>
#include <iostream>

int main() {
    int fd[2];
    pipe(fd); // 创建管道
    
    if (fork() == 0) { // 子进程
        close(fd[0]);   // 关闭读端
        write(fd[1], "Hello", 6);
        close(fd[1]);
    } else { // 父进程
        close(fd[1]);   // 关闭写端
        char buf[20];
        read(fd[0], buf, sizeof(buf));
        std::cout << "Received: " << buf << std::endl;
        close(fd[0]);
    }
    return 0;
}

1.2 命名管道(FIFO)

命名管道克服了匿名管道的限制:

  • 有文件名与之关联
  • 可用于无亲缘关系的进程间通信
  • 通过文件系统实现
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

// 进程1: 创建并写入FIFO
mkfifo("/tmp/myfifo", 0666);
int fd = open("/tmp/myfifo", O_WRONLY);
write(fd, "Hello FIFO", 10);
close(fd);

// 进程2: 读取FIFO
int fd = open("/tmp/myfifo", O_RDONLY);
char buf[20];
read(fd, buf, sizeof(buf));
close(fd);

2. 消息队列(Message Queue)

消息队列提供了一种结构化数据交换方式:

  • 消息被赋予类型,可按类型接收
  • 独立于发送和接收进程存在
  • 克服了管道无格式字节流的限制
#include <sys/ipc.h>
#include <sys/msg.h>
#include <iostream>

struct message {
    long mtype;
    char mtext[100];
};

int main() {
    key_t key = ftok("progfile", 65);
    int msgid = msgget(key, 0666 | IPC_CREAT);
    
    message msg;
    msg.mtype = 1;
    sprintf(msg.mtext, "Hello Message Queue");
    
    // 发送消息
    msgsnd(msgid, &msg, sizeof(msg.mtext), 0);
    
    // 接收消息
    msgrcv(msgid, &msg, sizeof(msg.mtext), 1, 0);
    std::cout << "Received: " << msg.mtext << std::endl;
    
    // 删除消息队列
    msgctl(msgid, IPC_RMID, NULL);
    return 0;
}

3. 共享内存(Shared Memory)

共享内存是最快的IPC方式:

  • 多个进程访问同一块物理内存
  • 不涉及数据复制
  • 需要同步机制配合使用
#include <sys/ipc.h>
#include <sys/shm.h>
#include <iostream>

int main() {
    key_t key = ftok("shmfile", 65);
    int shmid = shmget(key, 1024, 0666 | IPC_CREAT);
    
    // 附加共享内存
    char *str = (char*)shmat(shmid, (void*)0, 0);
    
    std::cout << "Write Data: ";
    std::cin.getline(str, 1024);
    
    std::cout << "Data in memory: " << str << std::endl;
    
    // 分离共享内存
    shmdt(str);
    
    // 删除共享内存
    shmctl(shmid, IPC_RMID, NULL);
    return 0;
}

4. 信号量(Semaphore)

信号量用于进程间同步:

  • 控制对共享资源的访问
  • 避免竞争条件
  • 可以是二进制或计数信号量
#include <sys/ipc.h>
#include <sys/sem.h>
#include <iostream>

union semun {
    int val;
    struct semid_ds *buf;
    unsigned short *array;
};

int main() {
    key_t key = ftok("semfile", 65);
    int semid = semget(key, 1, 0666 | IPC_CREAT);
    
    semun su;
    su.val = 1; // 初始值
    semctl(semid, 0, SETVAL, su);
    
    sembuf sb = {0, -1, 0}; // P操作
    semop(semid, &sb, 1);
    
    // 临界区代码
    std::cout << "In critical section" << std::endl;
    
    sb.sem_op = 1; // V操作
    semop(semid, &sb, 1);
    
    return 0;
}

5. 套接字(Socket)

套接字是最通用的IPC方式:

  • 可用于同一主机或不同主机上的进程通信
  • 支持多种协议(TCP/UDP)
  • 全双工通信
// 服务器端
#include <sys/socket.h>
#include <netinet/in.h>
#include <iostream>

int main() {
    int server_fd = socket(AF_INET, SOCK_STREAM, 0);
    
    sockaddr_in address;
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(8080);
    
    bind(server_fd, (struct sockaddr*)&address, sizeof(address));
    listen(server_fd, 3);
    
    int new_socket = accept(server_fd, NULL, NULL);
    char buffer[1024] = {0};
    read(new_socket, buffer, 1024);
    std::cout << "Message: " << buffer << std::endl;
    
    close(new_socket);
    close(server_fd);
    return 0;
}

// 客户端
#include <sys/socket.h>
#include <arpa/inet.h>

int main() {
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    
    sockaddr_in serv_addr;
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(8080);
    inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr);
    
    connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
    send(sock, "Hello Socket", 12, 0);
    
    close(sock);
    return 0;
}

6. 信号(Signal)

信号是异步通知机制:

  • 用于通知进程发生了某种事件
  • 有限种类的预定义信号
  • 不能传递复杂数据
#include <signal.h>
#include <unistd.h>
#include <iostream>

void handler(int sig) {
    std::cout << "Received signal: " << sig << std::endl;
}

int main() {
    signal(SIGINT, handler); // 注册信号处理函数
    
    std::cout << "Waiting for signal..." << std::endl;
    pause(); // 等待信号
    
    return 0;
}

7. 文件锁(File Locking)

文件锁用于协调对文件的访问:

  • 避免多个进程同时修改同一文件
  • 可以是建议锁或强制锁
  • 支持共享锁和排他锁
#include <sys/file.h>
#include <fcntl.h>
#include <unistd.h>
#include <iostream>

int main() {
    int fd = open("testfile.txt", O_RDWR | O_CREAT, 0666);
    
    // 获取排他锁
    if (flock(fd, LOCK_EX) == -1) {
        perror("flock");
        return 1;
    }
    
    // 临界区操作
    write(fd, "Hello File Lock", 15);
    
    // 释放锁
    flock(fd, LOCK_UN);
    close(fd);
    
    return 0;
}

8. Windows特有的IPC机制

8.1 邮槽(Mailslot)

  • 单向通信
  • 基于消息
  • 主要用于广播消息
// 服务器端
HANDLE hMailslot = CreateMailslot(
    "\\\\.\\mailslot\\sample_mailslot",
    0,
    MAILSLOT_WAIT_FOREVER,
    NULL);

// 客户端
HANDLE hFile = CreateFile(
    "\\\\.\\mailslot\\sample_mailslot",
    GENERIC_WRITE,
    FILE_SHARE_READ,
    NULL,
    OPEN_EXISTING,
    FILE_ATTRIBUTE_NORMAL,
    NULL);

8.2 内存映射文件(Memory-Mapped File)

类似于共享内存,但有文件支持

// 创建者
HANDLE hFile = CreateFile("shared.dat", ...);
HANDLE hMap = CreateFileMapping(hFile, ...);
LPVOID pBuf = MapViewOfFile(hMap, ...);

// 访问者
HANDLE hMap = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, "SharedMemory");
LPVOID pBuf = MapViewOfFile(hMap, ...);

9. 高级IPC技术

9.1 D-Bus

  • 高级消息总线系统
  • 主要用于桌面环境中的进程通信
  • 支持远程对象调用
#include <dbus/dbus.h>

DBusConnection* conn = dbus_bus_get(DBUS_BUS_SESSION, NULL);
dbus_bus_request_name(conn, "com.example.Service", 0, NULL);

DBusMessage* msg = dbus_message_new_signal(
    "/com/example/Object",
    "com.example.Interface",
    "SignalName");
    
dbus_connection_send(conn, msg, NULL);
dbus_message_unref(msg);

9.2 CORBA

  • 公共对象请求代理体系结构
  • 支持跨语言、跨平台的分布式对象通信
  • 使用IDL定义接口
// IDL定义
interface Hello {
    string sayHello();
};

// C++实现
class HelloImpl : public virtual POA_Hello {
public:
    char* sayHello() {
        return CORBA::string_dup("Hello CORBA!");
    }
};

10. IPC方式比较与选择指南

IPC方式适用场景优点缺点
管道父子进程间简单通信简单易用单向通信,只能亲缘进程
命名管道任意进程间简单通信可用于无亲缘进程仍然是单向通信
消息队列结构化消息传递消息有类型,可非阻塞读取系统范围限制(队列数量、大小)
共享内存高性能大数据量通信最快IPC方式需要额外同步机制
信号量进程同步有效解决竞争条件不直接传输数据
套接字网络或本地进程通信最通用,支持不同主机开销较大
信号异步事件通知简单通知机制信息量有限
文件锁文件访问协调简单文件同步粒度较粗
D-Bus桌面环境进程通信高级抽象,支持远程调用复杂度高
CORBA分布式系统,跨语言通信语言中立,支持复杂对象重量级,学习曲线陡峭

选择建议

  • 简单通信:考虑管道或命名管道
  • 结构化消息:使用消息队列
  • 高性能数据共享:共享内存+信号量
  • 网络或通用通信:套接字
  • 桌面应用:D-Bus
  • 企业级分布式系统:CORBA或类似技术

11. 安全考虑

  • 权限控制:设置适当的文件权限和IPC对象权限
  • 输入验证:验证接收到的所有数据
  • 资源限制:防止IPC资源耗尽攻击
  • 加密敏感数据:特别是通过网络或共享内存传输时
  • 最小特权原则:只授予必要的访问权限

12. 性能优化技巧

  • 减少数据复制:优先考虑共享内存
  • 批量处理:合并小消息为大批次
  • 异步通信:避免阻塞等待
  • 适当缓冲区大小:避免频繁重新分配
  • 选择轻量级协议:如UDP而非TCP(如果适用)

13. 跨平台考虑

  • 抽象层:为不同平台实现统一的IPC接口
  • 条件编译:使用预处理器指令处理平台差异
  • 第三方库:如Boost.Interprocess提供跨平台IPC
  • 测试:在所有目标平台上充分测试

14. 实际应用案例

14.1 多进程日志系统

  • 使用共享内存存储日志缓冲区
  • 信号量控制并发访问
  • 日志写入进程和日志读取/处理进程分离

14.2 分布式计算

  • 主进程通过消息队列分发任务
  • 工作进程通过共享内存返回结果
  • 信号量同步任务状态

14.3 微服务架构

  • 使用D-Bus或gRPC进行服务间通信
  • 共享内存用于高性能数据交换
  • 信号量协调资源访问

15. 总结

C++提供了丰富的进程间通信机制,从简单的管道到复杂的分布式对象系统。选择适当的IPC技术需要考虑以下因素:

  • 通信模式:单向/双向,同步/异步
  • 数据量:小消息还是大数据块
  • 性能要求:延迟和吞吐量需求
  • 进程关系:是否有亲缘关系
  • 平台限制:目标操作系统和环境

理解各种IPC技术的优缺点和适用场景,可以帮助开发者构建高效、可靠的进程间通信系统。在实际项目中,往往需要组合使用多种IPC技术来满足不同的通信需求。# C++ 进程间通信(IPC)方式全面解析

到此这篇关于C++ 进程间通信IPC的实现示例的文章就介绍到这了,更多相关C++ 进程间通信IPC内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:

相关文章

  • C++中vector的常用接口详析说明

    C++中vector的常用接口详析说明

    vector类我们可以将其看作是一个能够动态扩容的数组,下面这篇文章主要给大家介绍了关于 C++ vector常用接口的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-08-08
  • C++ std::condition_variable 条件变量用法解析

    C++ std::condition_variable 条件变量用法解析

    condition_variable(条件变量)是 C++11 中提供的一种多线程同步机制,它允许一个或多个线程等待另一个线程发出通知,以便能够有效地进行线程同步,这篇文章主要介绍了C++ std::condition_variable 条件变量用法,需要的朋友可以参考下
    2023-09-09
  • 关于C语言动态内存管理介绍

    关于C语言动态内存管理介绍

    大家好,本篇文章主要讲的是关于C语言动态内存管理介绍,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下
    2022-01-01
  • 浅析c#中如何在form的webbrowser控件中获得鼠标坐标

    浅析c#中如何在form的webbrowser控件中获得鼠标坐标

    以下是对c#中如何在form的webbrowser控件中获得鼠标坐标的实现方法进行了详细的分析介绍,需要的朋友可以参考下
    2013-07-07
  • VC通过托盘图标得到该所属进程的实现代码

    VC通过托盘图标得到该所属进程的实现代码

    这篇文章主要介绍了VC通过托盘图标得到该所属进程的实现代码,为了方便大家使用特将多个代码分享给大家,需要的朋友可以参考下
    2021-10-10
  • C++ STL中的容器适配器实现

    C++ STL中的容器适配器实现

    这篇文章主要介绍了C++ STL中的容器适配器实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-04-04
  • C++中 map的基本操作

    C++中 map的基本操作

    map是一类关联式容器。接下来通过本文给大家分享c++中的map基本操作,需要的朋友参考下
    2017-05-05
  • C/C++标准库之转换UTC时间到local本地时间详解

    C/C++标准库之转换UTC时间到local本地时间详解

    最近遇到一个问题:数据库中存放的时间为UTC时间,但是现在要求都出来显示的时间为本地时间,所以就用C++实现了,下面这篇文章主要给大家介绍了关于C/C++标准库之转换UTC时间到local本地时间的方法,还有C++中获取UTC时间精确到微秒的实现代码,需要的朋友可以参考下。
    2017-11-11
  • C语言之实现栈的基础创建

    C语言之实现栈的基础创建

    这篇文章主要介绍了C语言之实现栈的基础创建,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-07-07
  • Linux系统下如何使用C++解析json文件详解

    Linux系统下如何使用C++解析json文件详解

    JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式。下面这篇文章主要给大家介绍了关于Linux系统下如何使用C++解析json文件的相关资料,需要的朋友可以参考下
    2021-06-06

最新评论