Unix Domain Socket ,知识体系一共包含哪些部分?底层原理是什么?
·
Unix Domain Socket(简称 UDS)是类 Unix 系统(Linux、macOS 等)中一种进程间通信(IPC, Inter-Process Communication) 的核心机制。它允许同一台机器上的两个进程通过文件系统路径进行高效、安全的数据交换。
虽然名字中有 “Socket”,但它不经过网络协议栈,性能远高于 TCP/IP loopback(localhost),广泛用于数据库(如 PostgreSQL、MySQL)、Web 服务(PHP-FPM、Supervisor)、容器通信等场景。
一、知识体系构成(共 7 大部分)
1. 基本概念与作用
- 定义:
Unix Domain Socket 是一种本地进程间通信机制,使用文件系统路径作为地址(如/tmp/mysql.sock)。 - 核心作用:
- 同主机进程通信
- 替代本地 TCP 连接(
127.0.0.1:3306→/tmp/mysql.sock) - 提高性能、增强安全性
- 类比:
- TCP Socket:
IP + Port→ 网络通信 - Unix Socket:
Path→ 本地通信
- TCP Socket:
2. 类型与通信模式
| 类型 | 对应常量 | 特点 | 应用场景 |
|---|---|---|---|
| 流式套接字 | SOCK_STREAM |
面向连接,可靠,字节流(类似 TCP) | MySQL、Supervisor、HTTP Server |
| 数据报套接字 | SOCK_DGRAM |
无连接,消息边界(类似 UDP) | 简单消息传递 |
| 顺序包套接字 | SOCK_SEQPACKET |
保留消息边界 + 可靠传输(较少用) | 特定协议 |
✅ 最常用的是
SOCK_STREAM
3. 地址结构:struct sockaddr_un
用于绑定和连接的地址结构:
struct sockaddr_un {
sa_family_t sun_family; // AF_UNIX
char sun_path[108]; // 路径,如 "/tmp/app.sock"
};
sun_family = AF_UNIX:表示使用 Unix Domain Socketsun_path:最大 108 字节(Linux),路径过长会失败
4. 创建与通信流程(C 语言层面)
服务端(Server):
int sock = socket(AF_UNIX, SOCK_STREAM, 0);
struct sockaddr_un addr = { .sun_family = AF_UNIX };
strcpy(addr.sun_path, "/tmp/my.sock");
bind(sock, (struct sockaddr*)&addr, sizeof(addr));
listen(sock, 5);
int client_fd = accept(sock, NULL, NULL);
// read/write
客户端(Client):
int sock = socket(AF_UNIX, SOCK_STREAM, 0);
struct sockaddr_un addr = { .sun_family = AF_UNIX };
strcpy(addr.sun_path, "/tmp/my.sock");
connect(sock, (struct sockaddr*)&addr, sizeof(addr));
// send/recv
类似 TCP,但使用
AF_UNIX和路径
5. 文件系统与生命周期
- Socket 文件:
- 是一个特殊类型的文件(
ls -l显示为s) - 示例:
srwxr-xr-x 1 user user 0 Apr 5 10:00 /tmp/app.sock s表示 socket 文件
- 是一个特殊类型的文件(
- 生命周期:
- 服务端
bind()时创建 - 服务端关闭时自动删除(或需手动)
- 若未清理,下次启动报错
Address already in use
- 服务端
⚠️ 常见错误:
bind: Address already in use→ 手动删除残留.sock文件
6. 权限与安全机制
- 文件权限控制:
- 可设置
chmod、chown - 控制哪些用户/组可以连接
- 可设置
- 优势:
- 不暴露网络端口
- 防止外部扫描和攻击
- 适合容器、本地服务隔离
- 典型应用:
- Docker:
/var/run/docker.sock(仅 root 可访问) - Supervisor:
/var/run/supervisor.sock - PHP-FPM:
/run/php/php8.1-fpm.sock
- Docker:
7. 与 TCP Socket 的对比
| 特性 | Unix Domain Socket | TCP Socket(localhost) |
|---|---|---|
| 通信范围 | 仅本机 | 本机或远程 |
| 性能 | ⭐ 极高(无网络协议栈) | 较低(经过 TCP/IP 栈) |
| 安全性 | ⭐ 高(文件权限控制) | 中(需防火墙、密码) |
| 配置复杂度 | 中(路径管理) | 简单(IP+Port) |
| 调试工具 | nc、socat、lsof |
telnet、curl、netstat |
| 跨主机 | ❌ 不支持 | ✅ 支持 |
| 文件系统依赖 | ✅ 依赖路径 | ❌ 无 |
✅ 结论:本地通信优先使用 Unix Socket
二、底层原理详解
1. 内核实现机制
- Unix Socket 由操作系统内核实现,位于 传输层之下
- 数据在内核空间直接拷贝,不经过网卡、IP、TCP/UDP
- 使用 消息队列 在进程间传递数据
- 支持 文件描述符传递(
SCM_RIGHTS)——这是 TCP 不具备的强大功能
文件描述符传递示例:
// 服务端可以将打开的文件 fd 发送给客户端
sendmsg(sockfd, &msg, 0);
用于进程间共享资源(如日志文件、数据库连接)
2. 两种路径类型
| 类型 | 说明 |
|---|---|
| 路径名 socket | 普通路径,如 /tmp/app.sock,会创建文件 |
| 抽象 socket(Linux 特有) | 路径以 \0 开头,不创建文件系统条目,如 \0hidden |
抽象 socket 不占用文件系统,但仅 Linux 支持
3. 性能优势原理
TCP Loopback 流程:
应用 → Socket → TCP → IP → 网络驱动 → 回环接口 → IP → TCP → Socket → 应用
Unix Socket 流程:
应用 → VFS → 内核消息队列 → 应用
- 减少 6 层协议处理
- 零拷贝优化(
copy_to_user次数少) - 延迟更低,吞吐更高
实测性能:Unix Socket 比 TCP localhost 快 30%~50%
4. 系统调用与内核接口
| 系统调用 | 作用 |
|---|---|
socket(AF_UNIX, SOCK_STREAM, 0) |
创建 socket |
bind() |
绑定到路径 |
listen() / accept() |
监听和接受连接 |
connect() |
客户端连接 |
send() / recv() |
数据传输 |
close() |
关闭连接(自动删除 socket 文件) |
所有调用由内核
af_unix.c模块处理(Linux 源码)
5. 文件描述符传递(SCM_RIGHTS)
这是 Unix Socket 的高级特性,允许进程间传递“打开的文件”或“socket”:
struct msghdr msg = {0};
struct cmsghdr *cmsg;
char cmsg_buf[CMSG_SPACE(sizeof(int))];
msg.msg_control = cmsg_buf;
msg.msg_controllen = sizeof(cmsg_buf);
cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
*(int*)CMSG_DATA(cmsg) = fd_to_send;
sendmsg(sockfd, &msg, 0);
用途:Nginx 将连接传递给 PHP-FPM worker
三、典型应用场景
| 应用 | 使用方式 |
|---|---|
| MySQL / PostgreSQL | /tmp/mysql.sock 替代 127.0.0.1:3306 |
| Supervisor | /var/run/supervisor.sock 管理进程 |
| Docker | /var/run/docker.sock 控制 Docker 引擎 |
| PHP-FPM | Nginx 通过 /run/php/php-fpm.sock 转发请求 |
| Laravel Horizon | 内部通信 |
| Systemd | 服务间通信(如 journald) |
四、常见命令与调试工具
| 命令 | 作用 |
|---|---|
lsof /tmp/app.sock |
查看谁在使用 socket |
netstat -x |
列出所有 Unix Socket |
ss -x |
更现代的替代(推荐) |
socat - UNIX-CONNECT:/tmp/app.sock |
手动发送数据 |
strace -p <pid> |
跟踪 socket 系统调用 |
file /tmp/app.sock |
查看文件类型 |
五、总结:知识体系图谱
Unix Domain Socket 知识体系
├── 核心概念
│ ├── 本地 IPC 机制
│ └── 文件路径作为地址
├── 通信类型
│ ├── SOCK_STREAM(流)
│ ├── SOCK_DGRAM(数据报)
│ └── SOCK_SEQPACKET
├── 地址结构
│ └── struct sockaddr_un
├── 创建流程
│ ├── socket() → bind() → listen() → accept()
│ └── connect()
├── 底层原理
│ ├── 内核消息队列
│ ├── 零网络开销
│ ├── 文件描述符传递(SCM_RIGHTS)
│ └── 抽象 socket
├── 安全与权限
│ ├── chmod / chown
│ └── 防外部访问
├── 对比 TCP
│ ├── 性能更高
│ ├── 更安全
│ └── 仅本地
└── 典型应用
├── 数据库
├── Web 服务
├── 容器
└── 进程管理(Supervisor)
六、最佳实践建议
- ✅ 本地服务优先使用 Unix Socket
- ✅ 设置合理权限:
chmod 600,chown www-data:www-data - ✅ 使用
/var/run/或/tmp/标准路径 - ✅ 程序退出时自动清理 socket 文件
- ✅ 在 Docker 中通过 volume 共享 socket(如
/var/run/docker.sock) - ✅ 避免路径过长(< 108 字符)
更多推荐

所有评论(0)