1. 数据格式与边界
- 管道(pipe):数据是一串连续的字节,没有分条。写多少可以一次读,也可以分多次读。
- 消息队列:数据是一条条的消息,消息有类型和长度。发一个消息,对方就是按消息一次性收,不会拆分。
2. 通信方式
- 管道:单向通信。无名管道只能亲缘进程间使用;命名管道(FIFO)可以不相关进程用,但仍然单向。要双向得建两个管道。
- 消息队列:支持双向通信。一个队列可以有多个进程收发消息,还能按类型选取消息。
3. 消息优先级和筛选
- 管道:没有优先级。谁先写谁先被读,顺序不会变。
- 消息队列:支持按类型或优先级拿消息,接收方可以指定只收特定类型的消息,也可以顺序收。
4. 数据大小限制
- 管道:限制主要来自内核缓存(常见4KB~64KB),数据被读出就没了。没有“最大消息”的说法。
- 消息队列:每条消息/整个队列/系统都有最大长度限制(如8KB/16KB),这些可以通过系统参数查看和设置。
5. 生命周期
- 管道:随着进程结束而消失,没人用它了就被内核回收。
- 消息队列:只要不手动删除,就一直存在内核里,进程退出消息还在,直到被删除或系统重启。
6. 性能
- 管道:实现比较简单,系统开销小,就是数据的读写。
- 消息队列:有额外的消息管理和查找,所以系统开销稍大一些,但是用起来更灵活。
7. 典型适用场景
| 场景 | 推荐用法 |
|---|---|
| 只需要简单地传一串数据 | 管道 |
| 需要按类型/优先级处理请求 | 消息队列 |
| 多个进程需要彼此交互、按消息分发 | 消息队列(或socket) |
| 不相关进程间只需单向流式传输 | 命名管道(FIFO) |
| 需要很好地管理单条消息,或对粘包敏感 | 消息队列 |
8. 常用接口对比
| 操作 | 管道 | 消息队列 |
|---|---|---|
| 创建 | pipe(), mkfifo() | msgget(), mq_open() |
| 发送 | write() | msgsnd(), mq_send() |
| 接收 | read() | msgrcv(), mq_receive() |
| 关闭 | close() | msgctl(), mq_close()/mq_unlink() |
| 阻塞/非阻塞 | 支持O_NONBLOCK | 支持,可设非阻塞或超时 |