下面详细介绍 Unix Socket(Unix Domain Socket, UDS),包括其概念、特点、使用场景、API 交互方式、与 TCP/UDP 的对比、以及在 Linux 日志系统(如 rsyslog、journald)中的应用。
1. 什么是 Unix Socket
Unix Socket 是一种 进程间通信(IPC, Inter-Process Communication)机制 ,与 TCP/UDP 套接字类似,但只在 同一台主机上工作。
-
本质:
基于 文件系统路径 或 内核抽象命名空间 的通信端点。
-
协议族:
使用
AF_UNIX
或AF_LOCAL
协议族。 -
数据传输方式:
- 流式(SOCK_STREAM) :类似 TCP,保证有序、可靠。
- 数据报式(SOCK_DGRAM) :类似 UDP,但没有网络层,性能更高。
常见的 Unix Socket 文件路径:
路径 | 作用 |
---|---|
/dev/log |
传统 syslog 日志输入 |
/run/systemd/journal/syslog |
journald → rsyslog 日志转发 |
/var/run/docker.sock |
Docker CLI 与 Docker Daemon 通信 |
/tmp/mysql.sock |
MySQL 客户端与服务器通信 |
2. Unix Socket 与 TCP/UDP 的区别
特性 | Unix Socket | TCP Socket | UDP Socket |
---|---|---|---|
使用场景 | 同一台主机进程间通信 | 远程可靠传输 | 远程快速传输 |
协议族 | AF_UNIX |
AF_INET / AF_INET6 |
AF_INET / AF_INET6 |
寻址方式 | 文件路径或抽象命名空间 | IP + 端口 | IP + 端口 |
传输模式 | 流式 / 数据报 | 流式 | 数据报 |
可靠性 | 内核保证可靠传输 | TCP 协议保证 | 无连接,不可靠 |
性能 | 最快(无网络栈) | 慢于 Unix Socket | 快于 TCP,慢于 Unix Socket |
典型路径 | /dev/log 、/var/run/docker.sock |
127.0.0.1:80 |
127.0.0.1:514 |
结论:
如果客户端和服务端在同一主机上,Unix Socket 是首选,因为它无需网络协议栈,性能高、延迟低。
3. Unix Socket 的类型
Unix Socket 有三种主要类型:
类型 | 宏定义 | 特点 | 使用场景 |
---|---|---|---|
流式 Socket | SOCK_STREAM |
面向连接,可靠,有序,类似 TCP | rsyslog imuxsock 、Docker、MySQL |
数据报 Socket | SOCK_DGRAM |
无连接,消息边界保留,类似 UDP | 传统 syslog |
原始 Socket | SOCK_RAW |
底层通信,需要 root 权限 | 调试或特殊应用 |
4. Unix Socket 工作原理
4.1 流程示例
一个典型的 Unix Socket 通信过程(客户端 ↔ 服务端):
scss
Client Kernel Server
| | |
| socket(AF_UNIX) | |
|------------------------->| |
| | |
| connect("/dev/log") | |
|------------------------->| |
| | |
| 数据写入 write() | |
|------------------------->| recvfrom() |
| |------------------------>|
4.2 地址结构:sockaddr_un
Unix Socket 使用 struct sockaddr_un
来指定 socket 地址:
arduino
struct sockaddr_un {
sa_family_t sun_family; // AF_UNIX
char sun_path[108]; // 文件路径,如 /dev/log
};
特点:
-
sun_path
存储的是文件系统路径。 -
也可以使用 Linux 特有的 抽象命名空间:
sun_path[0] = '\0'
,后续字节为名称。- 不会在文件系统上生成实际文件。
- 例如:
"\0my_socket"
。
5. Unix Socket 在 rsyslog 中的应用
5.1 rsyslog 本地日志收集
rsyslog 使用 imuxsock
模块监听 /dev/log
:
scss
App (logger, sshd, cron)
|
| syslog() 调用
V
/dev/log (Unix Socket)
|
| <-- imuxsock 模块监听
V
rsyslog 处理规则
配置:
ini
module(load="imuxsock") # 加载 imuxsock 模块
5.2 journald 与 rsyslog 协作
现代 Linux 发行版使用 systemd-journald 作为第一级日志收集器。
日志流向如下:
arduino
App → /dev/log (Unix Socket) → journald
|
V
/run/systemd/journal/syslog → imuxsock → rsyslog
在这种模式下,rsyslog 实际监听
/run/systemd/journal/syslog
。
6. Unix Socket 实例演示
6.1 服务器端
c
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#define SOCKET_PATH "/tmp/unix_demo.sock"
int main() {
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (fd < 0) {
perror("socket");
exit(1);
}
struct sockaddr_un addr;
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, SOCKET_PATH);
unlink(SOCKET_PATH); // 确保路径不存在
if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
perror("bind");
exit(1);
}
listen(fd, 5);
printf("Server listening on %s\n", SOCKET_PATH);
int client_fd = accept(fd, NULL, NULL);
char buf[128];
read(client_fd, buf, sizeof(buf));
printf("Received: %s\n", buf);
close(client_fd);
close(fd);
unlink(SOCKET_PATH);
return 0;
}
6.2 客户端
c
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define SOCKET_PATH "/tmp/unix_demo.sock"
int main() {
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (fd < 0) {
perror("socket");
exit(1);
}
struct sockaddr_un addr;
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, SOCKET_PATH);
if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
perror("connect");
exit(1);
}
char *msg = "Hello Unix Socket!";
write(fd, msg, strlen(msg));
close(fd);
return 0;
}
运行结果:
shell
$ ./server
Server listening on /tmp/unix_demo.sock
$ ./client
$ ./server
Received: Hello Unix Socket!
7. 性能与优势
7.1 性能
-
Unix Socket 性能优于 TCP/UDP,因为:
- 不需要 IP 协议栈处理。
- 内核直接在进程之间传递数据,零拷贝开销更低。
- 同机通信延迟极低。
测试对比(本机 1KB 消息):
方式 | 延迟 | 吞吐量 |
---|---|---|
TCP 127.0.0.1 | ~10-15 μs | 150K msg/s |
UDP 127.0.0.1 | ~5-7 μs | 300K msg/s |
Unix Socket | ~2-3 μs | 500K msg/s |
8. 常见问题 FAQ
Q1: Unix Socket 文件丢失了怎么办?
-
如果
/dev/log
被删除或覆盖,rsyslog
无法接收日志。 -
解决办法:
sudo systemctl restart rsyslog
Q2: 如何查看 Unix Socket 是否存在?
bash
$ ss -x
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port
u_str ESTAB 0 0 /run/systemd/journal/stdout 42129 /run/systemd/journal/stdout 42128
u_str LISTEN 0 4096 /run/systemd/journal/syslog *
u_str LISTEN 0 4096 /dev/log *
Q3: 抽象命名空间有什么用?
- 抽象命名空间不会在文件系统生成文件,socket 文件不会占用磁盘路径。
- 常用于高安全或临时通信场景。
- 示例路径:
"\0hidden_socket"
。
9. 总结
关键点 | 说明 |
---|---|
定义 | Unix Socket 是一种本地进程间通信机制,基于文件路径寻址 |
性能 | 比 TCP/UDP 更快,延迟最低 |
类型 | 流式(SOCK_STREAM)、数据报(SOCK_DGRAM)、原始(SOCK_RAW) |
典型应用 | /dev/log 、Docker、MySQL、systemd journald |
与网络协议对比 | 无需 IP 协议栈,只能在同一主机使用 |
总结结论:
Unix Socket 是 Linux 系统中高效、稳定、广泛使用的 IPC 机制,尤其在日志系统、容器管理、数据库通信等场景中不可替代。