本页目录
管道与 socketpair
覆盖: pipe → socketpair (AF_UNIX) → splice → pipe capacity → AF_UNIX vs TCP → 性能考量 适用: Linux 用户态 IPC
概述
管道和 Unix domain socket 是 Linux 上最常用的本地 IPC 机制。管道适合单向数据流(父子进程),socketpair 适合双向通信。理解它们的内核实现差异(pipe 基于 pipefs,Unix socket 基于 VFS + 独立协议栈)对选择正确的 IPC 很重要。
pipe: 单向管道
int pipefd;
; // pipefd[0]=读端, pipefd[1]=写端
// 或: pipe2(pipefd, O_NONBLOCK | O_CLOEXEC);
; // 写入
; // 读取
// 默认 pipe capacity: 16 pages (64KB on 4KB pages)
// 可调整: fcntl(fd, F_SETPIPE_SZ, size)
pipe 内部
// fs/pipe.c
// 每个 pipe = 一个 pipe_inode_info:
// 环形缓冲区 (16 pages default)
// 读者等数据 → 放在 wait queue → 写者来了 → 唤醒
// 写者等空间 → 放在 wait queue → 读者来了 → 唤醒
// pipe 容量:
cat /proc/sys/fs/pipe-max-size # 最大
; // 设为 1MB
splice: 零拷贝传输
// splice 是 pipe 的超级能力:
// 不经过用户空间 → FD1 → pipe → FD2
// 文件 → socket (sendfile 的底层):
; // 文件 → pipe
; // pipe → socket
// → 零拷贝: 数据从 page cache 直接到 socket buffer
socketpair: 双向管道
int sv;
;
// sv[0] ↔ sv[1] 双向通信
;
; // 收到 "hello"
// SOCK_STREAM: 可靠, 有序, 双向 (类似 TCP)
// SOCK_DGRAM: 不可靠, 保留边界 (类似 UDP)
// SOCK_SEQPACKET: 可靠 + 保留边界 (5.3+)
AF_UNIX Socket vs TCP
本地同一机器的进程通信:
AF_UNIX socket (Unix domain):
不走协议栈 → 只在内核中传递 sk_buff
延迟: ~2μs (vs TCP localhost ~10μs)
吞吐: ~5GB/s (vs TCP localhost ~2GB/s)
AF_UNIX 为什么快?
1. 无 TCP 状态机 (无 SYN/SYN-ACK/FIN)
2. 无 checksum (本地通信不需要)
3. 无流控/拥塞控制
4. 无 IP 分片/重组
AF_UNIX 的凭证传递 (SCM_CREDENTIALS):
sendmsg(sock, msg, 0) ← 附送 pid/uid/gid
接收端: recvmsg → SCM_CREDENTIALS → 信任发送者身份
→ DBus, systemd, polkit 都依赖这个
pipe vs socketpair vs eventfd
| pipe | socketpair (AF_UNIX) | eventfd | |
|---|---|---|---|
| 方向 | 单向 | 双向 | 单向信号 |
| 数据 | 字节流 | 字节流/消息 | 8-byte counter |
| capacity | 64KB+ | send buffer (默认 200KB) | 1 counter |
| splice | 支持 | 不支持 (4.x+ 部分支持) | 不支持 |
| 凭证传递 | 无 | 有 (SCM_CREDENTIALS) | 无 |
| epoll | 支持 | 支持 | 支持 |
参考
- man: pipe(2), socketpair(2), splice(2), unix(7)
- 源码:
fs/pipe.c,net/unix/af_unix.c
关键词: pipe, socketpair, AF_UNIX, splice, SCM_CREDENTIALS, pipe capacity, eventfd