Linux进程间通信(IPC)
简介
进程间通信(Inter-Process Communication,IPC)是指在不同进程之间传递数据或信号的机制。Linux 提供了多种 IPC 方式,每种方式都有其特点和适用场景。
IPC方式分类
Linux 中常见的 IPC 方式包括:
- 管道(Pipe):匿名管道,用于有亲缘关系的进程间通信
- 命名管道(FIFO):命名管道,可用于无亲缘关系的进程间通信
- 消息队列(Message Queue):消息队列,进程间传递结构化数据
- 信号量(Semaphore):用于进程同步和互斥
- 共享内存(Shared Memory):最快的 IPC 方式,多个进程共享同一块内存
- 信号(Signal):用于进程间异步通知
- 套接字(Socket):可用于本地和网络通信
- 内存映射(mmap):将文件映射到内存,实现进程间通信
1. 管道(Pipe)
特点
- 半双工通信(数据只能单向流动)
- 只能用于有亲缘关系的进程(父子进程)
- 基于文件描述符
- 数据是流式的,无格式
创建和使用
1 |
|
示例
1 |
|
使用场景
- 父子进程间通信
- Shell 命令管道(如
ls | grep)
2. 命名管道(FIFO)
特点
- 有名字的管道,存在于文件系统中
- 可用于无亲缘关系的进程间通信
- 半双工通信
- 通过文件路径访问
创建和使用
1 | # 使用 mkfifo 命令创建 |
示例
创建 FIFO:
1 |
|
读取 FIFO:
1 |
|
使用场景
- 无亲缘关系的进程间通信
- 客户端-服务器模型
3. 消息队列
特点
- 消息队列是消息的链表,存储在内核中
- 每个消息队列用一个标识符(队列ID)来标识
- 消息是有格式的,可以按类型读取
- 支持多个进程读写
- 消息队列独立于进程存在
系统调用
1 |
|
消息结构
1 | struct msgbuf { |
示例
发送消息:
1 |
|
接收消息:
1 |
|
使用场景
- 需要按类型处理消息的场景
- 进程间传递结构化数据
- 解耦生产者和消费者
4. 信号量
特点
- 用于进程同步和互斥
- 是一个计数器,用于控制多个进程对共享资源的访问
- 支持多个信号量(信号量集)
- 原子操作,保证操作的原子性
系统调用
1 |
|
操作结构
1 | struct sembuf { |
示例
使用信号量实现互斥:
1 |
|
使用场景
- 进程同步
- 互斥访问共享资源
- 生产者-消费者问题
- 读者-写者问题
5. 共享内存
特点
- 最快的 IPC 方式,因为数据不需要在内核和用户空间之间复制
- 多个进程可以访问同一块内存区域
- 需要配合信号量或互斥锁使用,保证同步
- 数据在进程间直接共享
系统调用
1 |
|
示例
写入共享内存:
1 |
|
读取共享内存:
1 |
|
使用场景
- 需要高速数据传输的场景
- 大数据量共享
- 实时数据共享
6. 信号(Signal)
特点
- 异步通知机制
- 用于进程间通信和进程控制
- 信号是软件中断
- 有默认处理方式,可以自定义处理函数
常用信号
| 信号 | 值 | 说明 |
|---|---|---|
| SIGHUP | 1 | 挂起信号 |
| SIGINT | 2 | 中断信号(Ctrl+C) |
| SIGQUIT | 3 | 退出信号(Ctrl+\) |
| SIGKILL | 9 | 强制终止(不可捕获) |
| SIGTERM | 15 | 终止信号 |
| SIGUSR1 | 10 | 用户自定义信号1 |
| SIGUSR2 | 12 | 用户自定义信号2 |
系统调用
1 |
|
示例
信号处理:
1 |
|
发送信号:
1 |
|
使用场景
- 进程控制(终止、暂停、继续)
- 异步事件通知
- 进程间简单通信
7. 套接字(Socket)
特点
- 可用于本地进程间通信(Unix Domain Socket)
- 也可用于网络通信(Internet Socket)
- 全双工通信
- 支持多种协议(TCP、UDP、Unix Domain)
Unix Domain Socket
服务器端:
1 |
|
客户端:
1 |
|
使用场景
- 客户端-服务器模型
- 网络通信
- 本地进程间通信(Unix Domain Socket)
8. 内存映射(mmap)
特点
- 将文件映射到进程地址空间
- 多个进程可以映射同一个文件,实现共享
- 访问映射内存就像访问普通内存一样
- 可以用于大文件处理
系统调用
1 |
|
示例
写入进程:
1 |
|
读取进程:
1 |
|
使用场景
- 大文件处理
- 进程间共享数据
- 零拷贝文件I/O
IPC方式对比
| IPC方式 | 速度 | 容量 | 持久性 | 同步机制 | 适用场景 |
|---|---|---|---|---|---|
| 管道 | 慢 | 有限 | 否 | 自动 | 父子进程 |
| FIFO | 慢 | 有限 | 是 | 自动 | 无亲缘关系进程 |
| 消息队列 | 中 | 有限 | 是 | 自动 | 结构化消息 |
| 信号量 | 快 | - | 是 | 手动 | 同步互斥 |
| 共享内存 | 最快 | 大 | 是 | 手动 | 大数据共享 |
| 信号 | 快 | 小 | 否 | 异步 | 进程控制 |
| 套接字 | 中 | 大 | 是 | 手动 | 网络/本地通信 |
| mmap | 快 | 大 | 是 | 手动 | 文件共享 |
选择建议
- 父子进程通信:使用管道
- 无亲缘关系进程:使用 FIFO、消息队列或套接字
- 需要同步:使用信号量
- 大数据传输:使用共享内存或 mmap
- 进程控制:使用信号
- 网络通信:使用套接字
- 文件共享:使用 mmap
注意事项
- 资源清理:使用完 IPC 资源后要及时清理,避免资源泄漏
- 同步问题:共享内存和 mmap 需要配合信号量等同步机制使用
- 权限控制:注意 IPC 资源的权限设置,保证安全性
- 错误处理:所有 IPC 操作都要检查返回值,进行错误处理
- key值生成:使用
ftok()生成 key 时,要确保文件存在且可访问