当前位置: 首页 > news >正文

嵌入式Linux网络编程:UNIX Domain Socket进程间通信(IPC)


嵌入式Linux网络编程:UNIX Domain Socket进程间通信(IPC)

【本文代码已在Linux平台验证通过】


一、UNIX Domain Socket核心优势

1.1 本地IPC方案对比

特性UNIX Domain Socket管道(Pipe)消息队列(Message Queue)共享内存(Shared Memory)
跨进程通信✔️✔️✔️✔️
双向通信✔️❌(半双工)✔️✔️
支持字节流/数据报✔️(SOCK_STREAM/DGRAM)
传输效率★★★★★★★★★★★★★★★★★★
资源占用

二、UNIX Domain Socket核心原理

2.1 地址结构

struct sockaddr_un {
    sa_family_t sun_family;        // AF_UNIX
    char        sun_path[108];     // 套接字文件路径(如/tmp/my_socket)
};

2.2 通信流程

服务端 客户端 socket() bind() listen() socket() connect() accept() send() recv() close() close() 服务端 客户端

三、UNIX Domain Socket服务端实现

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

#define SOCKET_PATH "/tmp/unix_socket_example"  // 套接字文件路径
#define BUFFER_SIZE 128

int main() {
    int server_fd, client_fd;
    struct sockaddr_un serv_addr, cli_addr;
    socklen_t cli_len = sizeof(cli_addr);
    char buffer[BUFFER_SIZE];

    // 1. 创建Unix域流式套接字
    if ((server_fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
        perror("socket创建失败");
        exit(EXIT_FAILURE);
    }

    // 2. 配置地址结构
    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sun_family = AF_UNIX;
    strncpy(serv_addr.sun_path, SOCKET_PATH, sizeof(serv_addr.sun_path)-1);

    // 3. 确保文件不存在
    unlink(SOCKET_PATH);

    // 4. 绑定套接字
    if (bind(server_fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == -1) {
        perror("绑定失败");
        close(server_fd);
        exit(EXIT_FAILURE);
    }

    // 5. 设置监听队列(最大5个等待连接)
    if (listen(server_fd, 5) == -1) {
        perror("监听失败");
        close(server_fd);
        exit(EXIT_FAILURE);
    }
    printf("服务端已启动,等待客户端连接...\n");

    // 6. 接受客户端连接
    if ((client_fd = accept(server_fd, (struct sockaddr*)&cli_addr, &cli_len)) == -1) {
        perror("接受连接失败");
        close(server_fd);
        exit(EXIT_FAILURE);
    }
    printf("客户端已连接: %s\n", serv_addr.sun_path);

    // 7. 通信循环
    while (1) {
        ssize_t num_bytes = recv(client_fd, buffer, BUFFER_SIZE, 0);
        if (num_bytes == -1) {
            perror("接收错误");
            break;
        } else if (num_bytes == 0) {
            printf("客户端断开连接\n");
            break;
        }

        buffer[num_bytes] = '\0';
        printf("收到消息: %s\n", buffer);

        // 构造响应
        char reply[BUFFER_SIZE];
        snprintf(reply, sizeof(reply), "服务端已接收 %zd 字节", num_bytes);

        if (send(client_fd, reply, strlen(reply), 0) == -1) {
            perror("发送失败");
            break;
        }
    }

    // 8. 清理资源
    close(client_fd);
    close(server_fd);
    unlink(SOCKET_PATH);  // 删除套接字文件
    return 0;
}

四、UNIX Domain Socket客户端实现

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

#define SOCKET_PATH "/tmp/unix_socket_example"
#define BUFFER_SIZE 128

int main() {
    int sockfd;
    struct sockaddr_un serv_addr;
    char buffer[BUFFER_SIZE];

    // 1. 创建套接字
    if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
        perror("socket创建失败");
        exit(EXIT_FAILURE);
    }

    // 2. 配置服务端地址
    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sun_family = AF_UNIX;
    strncpy(serv_addr.sun_path, SOCKET_PATH, sizeof(serv_addr.sun_path)-1);

    // 3. 连接服务端
    if (connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == -1) {
        perror("连接失败");
        close(sockfd);
        exit(EXIT_FAILURE);
    }

    printf("已连接到服务端\n");

    // 4. 通信循环
    while (1) {
        printf("输入消息(输入exit退出): ");
        fgets(buffer, BUFFER_SIZE, stdin);
        buffer[strcspn(buffer, "\n")] = '\0';

        if (strcmp(buffer, "exit") == 0) break;

        // 发送数据
        if (send(sockfd, buffer, strlen(buffer), 0) == -1) {
            perror("发送失败");
            break;
        }

        // 接收响应
        ssize_t num_bytes = recv(sockfd, buffer, BUFFER_SIZE, 0);
        if (num_bytes == -1) {
            perror("接收失败");
            break;
        }

        buffer[num_bytes] = '\0';
        printf("服务端响应: %s\n", buffer);
    }

    close(sockfd);
    return 0;
}

五、核心API详解

5.1 socket()

int socket(int domain, int type, int protocol);
参数UNIX Domain Socket专用配置
domainAF_UNIX(必须)
typeSOCK_STREAM(可靠字节流)或 SOCK_DGRAM(数据报)
protocol通常填0

5.2 bind()

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  • 关键点:绑定的sun_path需有目录写权限(嵌入式系统常用/tmp/var/run

5.3 connect()与accept()

  • 连接特性:无需三次握手,内核直接复制路径名

六、编译与测试

6.1 编译命令

# 服务端
gcc unix_server.c -o server -Wall -O2

# 客户端
gcc unix_client.c -o client -Wall -O2

6.2 运行演示

# 终端1:启动服务端
$ ./server
服务端已启动,等待客户端连接...
客户端已连接: /tmp/unix_socket_example

# 终端2:启动客户端
$ ./client
已连接到服务端
输入消息(输入exit退出): Hello UNIX Socket!
服务端响应: 服务端已接收 15 字节
输入消息(输入exit退出): exit

七、嵌入式场景优化建议

7.1 提升安全性

// 设置套接字文件权限(0600仅允许所有者访问)
chmod(SOCKET_PATH, S_IRUSR | S_IWUSR);

7.2 抽象命名空间

// 使用抽象套接字名(Linux特有)
serv_addr.sun_path[0] = '\0';  // 第一个字符为NULL
strncpy(serv_addr.sun_path+1, "my_abstract_socket", sizeof(serv_addr.sun_path)-2);

7.3 多客户端处理

// 使用epoll实现多路复用
struct epoll_event ev;
epoll_fd = epoll_create1(0);
ev.events = EPOLLIN;
ev.data.fd = server_fd;
epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_fd, &ev);

八、常见问题排查

8.1 连接失败:Permission denied

# 检查套接字文件权限
ls -l /tmp/unix_socket_example
# 解决方案:
sudo chmod 777 /tmp/unix_socket_example

8.2 地址已在使用:Address already in use

# 强制删除残留套接字文件
rm -f /tmp/unix_socket_example

8.3 跨用户通信问题

  • 原因:Linux权限系统限制
  • 解决:设置用户组权限或使用sudo

扩展阅读
Linux Programmer’s Manual: unix(7) | POSIX IPC 标准 | Linux man-pages


通过本文,您可掌握UNIX Domain Socket在嵌入式Linux中的高效IPC实现方法。相比网络套接字,UDS在本地通信场景中性能更优、资源占用更少,非常适用于嵌入式设备的多模块协作!

相关文章:

  • Maven版本统一管理
  • 如何在Webpack中配置别名路径?
  • Google开源机器学习框架TensorFlow探索更多ViT优化
  • Ubuntu 系统无法远程连接?完整排查指南与解决方案
  • RedHat7.6_x86_x64服务器(最小化安装)搭建使用记录(二)
  • 51c自动驾驶~合集15
  • Modbus协议开发入门
  • LangChain基础系列之LLM接口详解:从原理到实战的全攻略
  • OSI 七层模型和四层模型(TCP/IP 模型)
  • 基于深度神经网络的图像防篡改检测方法研究
  • 无人驾驶汽车与智能化煤矿的发展对比及启示:技术革命下的产业升级路径
  • DeepSeek算法研发闭环解析:如何打造持续进化的AI生产线?
  • C# MemoryStream 使用详解
  • 爬虫的第三天——爬动态网页
  • ubuntu服务器进程启动失败的原因分析
  • LabVIEW医疗设备故障智能诊断系统
  • 智能网联交通加速落地,光路科技TSN技术助推车路云一体化发展
  • 电脑连不上手机热点会出现的小bug
  • vs2022+QT6.7.3打包程序流程
  • 推荐《人工智能算法》卷1、卷2和卷3 合集3本书(附pdf电子书下载)
  • 美国和沙特签署上千亿美元军售协议
  • 有关部门负责人就《新时代的中国国家安全》白皮书答记者问
  • 两部门部署中小学幼儿园教师招聘工作:吸纳更多高校毕业生从教
  • 金融监管局:已设立74支私募股权投资基金,支持投资科技创新企业
  • 江苏淮安优化村级资源配置:淮安区多个空心村拟并入邻村
  • 青岛双星名人集团董事长发公开信称家人逼迫交出管理权?公司回应