详解Unix Socket,已经与TCP/UDP 的区别

下面详细介绍 Unix Socket(Unix Domain Socket, UDS),包括其概念、特点、使用场景、API 交互方式、与 TCP/UDP 的对比、以及在 Linux 日志系统(如 rsyslog、journald)中的应用。


1. 什么是 Unix Socket

Unix Socket 是一种 进程间通信(IPC, Inter-Process Communication)机制 ,与 TCP/UDP 套接字类似,但只在 同一台主机上工作。

  • 本质:

    基于 文件系统路径内核抽象命名空间 的通信端点。

  • 协议族:

    使用 AF_UNIXAF_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,因为:

    1. 不需要 IP 协议栈处理。
    2. 内核直接在进程之间传递数据,零拷贝开销更低。
    3. 同机通信延迟极低。

测试对比(本机 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 机制,尤其在日志系统、容器管理、数据库通信等场景中不可替代。

相关推荐
轻松Ai享生活2 小时前
linux日志缺失排查流程
linux
进击的_鹏2 小时前
【Linux】基础指令和基础知识点
linux·运维·服务器
望获linux2 小时前
【Linux基础知识系列:第一百三十四篇】理解Linux的进程调度策略
java·linux·运维·服务器·数据库·mysql
峰顶听歌的鲸鱼2 小时前
24.Linux硬盘分区管理
linux·运维·服务器·笔记·学习方法
大聪明-PLUS2 小时前
关于Linux中的软链接和硬链接
linux·嵌入式·arm·smarc
路遥芝麻2 小时前
如何使用升腾C92主机搭建本地Linux编译服务器并通过Windows映射访问共享目录
linux·服务器·windows
ARM+FPGA+AI工业主板定制专家3 小时前
基于RK3576+FPGA的无人机飞控系统设计
linux·fpga开发·无人机·rk3588·rk3568
Anthony_2313 小时前
Dockerfile构建镜像以及网络
linux·运维·服务器·网络·docker
明月看潮生3 小时前
编程与数学 03-009 Linux 操作系统应用 16_Linux 邮件服务器
linux·运维·服务器·青少年编程·编程与数学