C++进程间通信方式全解析:从管道到套接字实战代码示例

引言

在操作系统中,进程间通信(IPC)是协调多进程协作的核心技术。不同的通信方式有各自的适用场景和性能特点。本文将通过代码实例详细讲解管道、消息队列、共享内存、信号量、信号和套接字等6种IPC方式,帮助开发者选择合适方案。


一、管道(Pipes)

1.1 匿名管道(无名管道)

特点

  • 仅限父子进程或兄弟进程间通信
  • 半双工通信,数据单向流动
  • 内核缓冲区大小有限(通常4KB)

C++代码示例

#include <unistd.h>
#include <sys/wait.h>
#include <cstring>

int main() {
    int pipe_fd[2];
    char buffer[100];
    if (pipe(pipe_fd) == -1) { // 创建管道
        perror("pipe");
        return 1;
    }

    pid_t pid = fork();
    if (pid == 0) { // 子进程读数据
        close(pipe_fd[1]); // 关闭写端
        read(pipe_fd[0], buffer, sizeof(buffer));
        printf("Child received: %s\n", buffer);
        close(pipe_fd[0]);
    } else { // 父进程写数据
        close(pipe_fd[0]); // 关闭读端
        const char* msg = "Hello from parent!";
        write(pipe_fd[1], msg, strlen(msg)+1);
        close(pipe_fd[1]);
        wait(NULL); // 等待子进程
    }
    return 0;
}

关键点pipe()返回两个文件描述符,pipe_fd[0]读,pipe_fd[1]


1.2 命名管道(FIFO)

特点

  • 通过文件系统路径标识
  • 无关进程可通信
  • 支持多读多写

C++代码示例

#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main() {
    const char* fifo_path = "/tmp/my_fifo";
    mkfifo(fifo_path, 0666); // 创建命名管道
    
    int fd = open(fifo_path, O_WRONLY);
    write(fd, "Hello FIFO!", 12);
    close(fd);
    return 0;
}

注意:需先运行mkfifo创建管道文件,读写方需分别以O_WRONLYO_RDONLY打开


二、消息队列(Message Queue)

特点

  • 消息按类型存储和读取
  • 支持异步通信
  • 存在消息长度和队列容量限制

C++线程安全队列实现

#include <queue>
#include <mutex>
#include <condition_variable>

template<typename T>
class SafeQueue {
private:
    std::queue<T> queue;
    std::mutex mtx;
    std::condition_variable cv;

public:
    void push(const T& item) {
        std::lock_guard<std::mutex> lock(mtx);
        queue.push(item);
        cv.notify_one();
    }

    T pop() {
        std::unique_lock<std::mutex> lock(mtx);
        cv.wait(lock, [this]{ return !queue.empty(); });
        T item = queue.front();
        queue.pop();
        return item;
    }
};

说明:使用std::mutexstd::condition_variable实现同步


三、共享内存(Shared Memory)

特点

  • 零拷贝,直接操作内存
  • 需配合信号量同步
  • 适用于大数据量传输

POSIX共享内存示例

#include <sys/mman.h>
#include <fcntl.h>
#include <cstring>

int main() {
    const char* name = "/my_shm";
    int fd = shm_open(name, O_CREAT | O_RDWR, 0666);
    ftruncate(fd, 1024); // 设置内存大小
    
    void* ptr = mmap(NULL, 1024, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    strcpy(static_cast<char*>(ptr), "Shared data"); // 写入数据
    
    munmap(ptr, 1024);
    close(fd);
    shm_unlink(name); // 删除共享内存对象
    return 0;
}

关键函数shm_open创建对象,mmap映射内存


四、信号量(Semaphore)

作用

  • 控制对共享资源的访问
  • 实现进程间互斥与同步

POSIX信号量示例

#include <semaphore.h>
#include <fcntl.h>

int main() {
    sem_t* sem = sem_open("/my_sem", O_CREAT, 0644, 1); // 初始值1
    sem_wait(sem); // P操作:获取信号量
    // 临界区代码
    sem_post(sem); // V操作:释放信号量
    sem_close(sem);
    sem_unlink("/my_sem");
    return 0;
}

注意:命名信号量通过路径标识,可用于无关进程


五、信号(Signal)

用途

  • 通知进程特定事件发生
  • SIGINT(Ctrl+C)、SIGTERM(终止信号)

信号处理示例

#include <csignal>
#include <unistd.h>

void handler(int sig) {
    printf("Received signal: %d\n", sig);
}

int main() {
    signal(SIGUSR1, handler); // 注册信号处理函数
    raise(SIGUSR1); // 发送信号
    return 0;
}

扩展kill()函数可向指定进程发送信号


六、套接字(Socket)

特点

  • 支持跨网络通信
  • 分为TCP(可靠)和UDP(高效)

TCP套接字示例

// 服务端
#include <sys/socket.h>
#include <netinet/in.h>

int main() {
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in addr{AF_INET, htons(8080), INADDR_ANY};
    bind(sockfd, (struct sockaddr*)&addr, sizeof(addr));
    listen(sockfd, 5);
    
    int client_fd = accept(sockfd, NULL, NULL);
    send(client_fd, "Hello client!", 13, 0);
    close(client_fd);
    close(sockfd);
    return 0;
}

流程socket()bind()listen()accept()send()/recv()


总结与选择建议
通信方式适用场景性能复杂度
管道父子进程简单通信
消息队列异步通信,松散耦合
共享内存大数据量、实时性要求高
信号量资源访问控制
套接字跨网络通信可变

开发建议:优先考虑共享内存+信号量组合处理高性能场景,简单通信可使用管道或信号。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值