计算机网络之从Socket到UDS

Socket

Socket是什么

Socket 是应用层与 TCP/IP 协议族通信的中间软件抽象层,它是一组编程接口(API),可以看作是主机间通信的端点。Socket 编程是网络应用开发的基础,几乎所有网络协议和应用程序都是基于 Socket 接口实现的。
请添加图片描述

Socket原理

请添加图片描述

Socket的系统调用

int socket(int domain, int type, int protocal)
  • domain:即协议域,又称为协议族(family)。 协议族决定了socket的地址类型,在通信中必须采用对应的地址,如AF_INET决定了要用ipv4地址(32位的)与端口号(16位的)的组合、AF_UNIX决定了要用一个绝对路径名作为地址。常用的地址族有:

    • AF_INET
    • AF_INET6
    • AF_LOCAL(AF_UNIX,本地通信用)
    • AF_ROUTE
  • type:信息传送方式。常用的信息传送方式有:

    • SOCK_STREAM
    • SOCK_DGRAM
    • SOCK_RAW
    • SOCK_PACKET
    • SOCK_SEQPACKET
  • protocol:对应协议。通常设置为0,让其自动匹配。

    • IPPROTO_TCP TCP传输协议
    • IPPROTO_UDP UDP传输协议
    • IPPROTO_SCTP STCP传输协议
    • IPPROTO_TIPCTIPC传输协议
  • 实现 TCP 字节流通信: socket 类型是 AF-INET 和 SOCK_STREAM;

  • 实现 UDP 数据报通信:socket 类型是 AF_INET 和 SOCK_DGRAM;

  • 实现本地进程间通信: 「本地字节流 socket」类型是 AF_LOCAL 和 SOCK_STREAM,「本地数据报socket 」类型是AF_LOCAL和SOCK_DGRAM。另外, AF_UNIX和AF_LOCAL是等价的,所以AF_UNIX 也属于本地 socket;

Unix domain socket

UNIX Domain Socket 详解:高效的进程间通信机制

一、UNIX Domain Socket 概述

UNIX Domain Socket(简称 UDS),又称 IPC socket,是一种基于 socket 框架发展而来的高效进程间通信(IPC)机制,专为同一主机上的进程通信设计。作为 POSIX 标准组件,它不仅限于 UNIX 系统,Linux 等现代操作系统也都提供了完善支持。

与网络 Socket 的关键区别

虽然传统网络 socket 通过 loopback 地址(127.0.0.1)也能实现本地进程通信,但 UDS 具有显著优势:

  1. 协议栈差异

    • 网络 socket:需要经过完整的 TCP/IP 协议栈处理
    • UDS:完全绕过网络协议栈,直接在内核中完成数据传递
  2. 数据传输效率

    • 网络 socket:需要打包/拆包、计算校验和、维护序列号和应答机制
    • UDS:直接将应用层数据从一个进程缓冲区拷贝到另一个进程缓冲区
  3. 性能表现

    • 实测表明 UDS 的传输效率比 loopback 网络 socket 快近一倍
    • 减少了至少两次数据拷贝(用户态-内核态-用户态)
  4. 可靠性

    • UDS 基于本地文件系统实现,不受网络环境影响
    • 内核保证数据传输的原子性和顺序性

二、UNIX Domain Socket 核心特性

1. 全双工通信

UDS 支持全双工工作模式,通信双方可以同时进行读写操作,这与管道(Pipe)等半双工 IPC 机制形成鲜明对比。

2. 丰富的 API 语义

继承自 BSD socket 的完整 API 体系,提供比传统 IPC 机制更灵活的控制能力:

  • 支持面向连接(SOCK_STREAM)和无连接(SOCK_DGRAM)两种模式
  • 提供 select/poll/epoll 等多路复用机制
  • 支持带外数据等高级特性

3. 文件系统集成

UDS 通过特殊的 socket 文件进行标识:

struct sockaddr_un {
    sa_family_t sun_family;    /* AF_UNIX */
    char sun_path[108];        /* 路径名 */
};

这种设计带来了额外优势:

  • 天然的权限控制(通过文件权限位)
  • 直观的进程间可见性(通过文件系统)
  • 持久化能力(虽然不常用)

4. 广泛的应用支持

已成为事实上的标准 IPC 机制:

  • X Window 系统(GUI 通信)
  • Docker/容器技术(控制面通信)
  • DBMS(如 MySQL 的本地连接)
  • 系统监控工具(如 Prometheus 的 node_exporter)

三、UNIX Domain Socket 编程详解

基本通信流程

服务器端流程

  1. 创建 socket:socket(AF_UNIX, SOCK_STREAM, 0)
  2. 绑定地址:bind() 指定 socket 文件路径
  3. 监听连接:listen()
  4. 接受连接:accept()
  5. 数据交换:read()/write()send()/recv()
  6. 关闭连接:close()

客户端流程

  1. 创建 socket
  2. 连接服务器:connect()
  3. 数据交换
  4. 关闭连接

关键系统调用

#include <sys/socket.h>
#include <sys/un.h>

// 创建socket
int socket(int domain, int type, int protocol);
// domain: AF_UNIX
// type: SOCK_STREAM(可靠连接)或SOCK_DGRAM(数据报)

// 地址绑定
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

// 连接建立
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

// 数据收发
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
ssize_t recv(int sockfd, void *buf, size_t len, int flags);

完整示例代码

服务器端 server.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>

#define SOCKET_PATH "/tmp/demo_socket"

int main() {
    int server_fd, client_fd;
    struct sockaddr_un server_addr, client_addr;
    socklen_t client_len;
    char buf[256];
    
    // 1. 创建socket
    server_fd = socket(AF_UNIX, SOCK_STREAM, 0);
    if (server_fd == -1) {
        perror("socket");
        exit(EXIT_FAILURE);
    }
    
    // 2. 绑定地址
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sun_family = AF_UNIX;
    strncpy(server_addr.sun_path, SOCKET_PATH, sizeof(server_addr.sun_path)-1);
    
    unlink(SOCKET_PATH); // 确保文件不存在
    if (bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) {
        perror("bind");
        close(server_fd);
        exit(EXIT_FAILURE);
    }
    
    // 3. 监听
    if (listen(server_fd, 5) == -1) {
        perror("listen");
        close(server_fd);
        exit(EXIT_FAILURE);
    }
    
    printf("Server listening...\n");
    
    // 4. 接受连接
    client_len = sizeof(client_addr);
    client_fd = accept(server_fd, (struct sockaddr*)&client_addr, &client_len);
    if (client_fd == -1) {
        perror("accept");
        close(server_fd);
        exit(EXIT_FAILURE);
    }
    
    // 5. 数据交换
    ssize_t num_read = read(client_fd, buf, sizeof(buf));
    printf("Received: %.*s\n", (int)num_read, buf);
    
    const char *msg = "Hello from server!";
    write(client_fd, msg, strlen(msg));
    
    // 6. 清理
    close(client_fd);
    close(server_fd);
    unlink(SOCKET_PATH);
    return 0;
}

客户端 client.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>

#define SOCKET_PATH "/tmp/demo_socket"

int main() {
    int sockfd;
    struct sockaddr_un addr;
    char buf[256];
    
    // 1. 创建socket
    sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
    if (sockfd == -1) {
        perror("socket");
        exit(EXIT_FAILURE);
    }
    
    // 2. 连接服务器
    memset(&addr, 0, sizeof(addr));
    addr.sun_family = AF_UNIX;
    strncpy(addr.sun_path, SOCKET_PATH, sizeof(addr.sun_path)-1);
    
    if (connect(sockfd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
        perror("connect");
        close(sockfd);
        exit(EXIT_FAILURE);
    }
    
    // 3. 数据交换
    const char *msg = "Hello from client!";
    write(sockfd, msg, strlen(msg));
    
    ssize_t num_read = read(sockfd, buf, sizeof(buf));
    printf("Received: %.*s\n", (int)num_read, buf);
    
    // 4. 清理
    close(sockfd);
    return 0;
}

四、高级特性与最佳实践

1. 性能优化技巧

  • 使用 sendmsg/recvmsg:支持分散/聚集IO,减少数据拷贝
  • 设置非阻塞模式:配合IO多路复用提高并发能力
  • 适当调整缓冲区大小:平衡内存使用和系统调用开销

2. 安全注意事项

  • 设置严格的文件权限(通常设为0700)
  • 验证对端进程身份(通过 getsockopt SO_PEERCRED)
  • 避免使用公共目录存放socket文件

3. 抽象socket命名空间

Linux 3.8+支持抽象socket命名空间:

addr.sun_path[0] = '\0';  // 第一个字节为null
strncpy(addr.sun_path+1, "abstract_name", sizeof(addr.sun_path)-2);

特点:

  • 不创建实际文件
  • 生命周期与内核相同
  • 自动清理

4. 与其它IPC机制对比

特性UDS管道共享内存消息队列
通信方向全双工半双工双向双向
数据边界保留字节流保留
访问控制文件权限文件权限系统权限
性能最高中低
复杂度

五、实际应用场景

  1. 微服务架构:同一主机上的服务间通信
  2. 安全沙箱:受限环境下的进程隔离与通信
  3. 高性能代理:Nginx等服务器与后端进程通信
  4. 设备控制:用户空间与内核模块的交互
  5. 桌面环境:GUI应用与后台服务通信

结语

UNIX Domain Socket 凭借其高效性、可靠性和丰富的功能特性,已成为现代操作系统中进程间通信的首选方案。无论是系统级开发还是应用层编程,深入理解 UDS 的工作原理和最佳实践,都能帮助开发者构建更高效、更可靠的本地通信系统。随着容器化技术的普及,UDS 在隔离环境通信中的作用将愈发重要。

参考文章

https://blog.youkuaiyun.com/weixin_39258979/article/details/80835555

https://xiaolincoding.com/os/4_process/process_commu.html#socket

https://www.cnblogs.com/sparkdev/p/8359028.html

https://blog.youkuaiyun.com/weixin_39258979/article/details/80931464

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值