本页目录

管道与 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[2];
pipe(pipefd);            // pipefd[0]=读端, pipefd[1]=写端

// 或: pipe2(pipefd, O_NONBLOCK | O_CLOEXEC);

write(pipefd[1], buf, len);  // 写入
read(pipefd[0], buf, len);   // 读取

// 默认 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  # 最大 capacity (默认 1MB)
fcntl(fd, F_SETPIPE_SZ, 1048576);  // 设为 1MB

splice: 零拷贝传输

// splice 是 pipe 的超级能力:
//   不经过用户空间 → FD1 → pipe → FD2

// 文件 → socket (sendfile 的底层):
splice(file_fd, &offset, pipefd[1], NULL, size, 0);  // 文件 → pipe
splice(pipefd[0], NULL, sock_fd, NULL, size, 0);     // pipe → socket
// → 零拷贝: 数据从 page cache 直接到 socket buffer

socketpair: 双向管道

#include <sys/socket.h>
int sv[2];
socketpair(AF_UNIX, SOCK_STREAM, 0, sv);

// sv[0] ↔ sv[1] 双向通信
write(sv[0], "hello", 5);
read(sv[1], buf, 5);     // 收到 "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

pipesocketpair (AF_UNIX)eventfd
方向单向双向单向信号
数据字节流字节流/消息8-byte counter
capacity64KB+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