自学内容网 自学内容网

【无标题】

进程间通讯:域套接字(Unix Domain Sockets)

一、简介

域套接字是一种在同一台机器上进行进程间通讯的机制(Inter-Process Communication, IPC),也称为本地套接字或文件系统套接字。与网络套接字不同,Unix套接字不需要经过网络协议栈,因此性能上更为高效。域套接字支持流(类似TCP)和数据报(类似UDP)两种模式;

​域套接字不经过网络协议栈是指数据传输不去要经过IP层的路由、不需要TCP/UDP等传输层协议的封包域解包处理,不需要网络接口层的参与,网络套接字则需要完成的网络协议栈处理;

二、原理图

普通网络套接字数据传输过程:
在这里插入图片描述
域套接字数据传输过程:

在这里插入图片描述

三、主要特点

  1. 本地通信:Unix 域套接字仅限于同一主机上的进程之间通信。
  2. 高性能:由于不经过网络协议栈,通信速度更快。
  3. 安全性:文件系统的权限管理可以用来控制访问。
  4. 灵活的数据传输:支持字节流(SOCK_STREAM)和数据报(SOCK_DGRAM)两种模式。
  5. 文件系统路径:每个 Unix 域套接字都有一个文件系统路径,可以在文件系统中查看和操作。

四、基本概念

  1. 套接字地址结构struct sockaddr_un 用于表示 Unix 域套接字的地址。
  2. 套接字类型
    • SOCK_STREAM:提供面向连接的、可靠的数据传输服务,类似于 TCP。
    • SOCK_DGRAM:提供无连接的、不可靠的数据报服务,类似于 UDP。

五、代码示例

1、客户端代码示例

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

// 信号处理器函数
void sigpipe_handler(int signum) {
    if (signum == SIGPIPE) {
        fprintf(stderr, "Caught SIGPIPE, connection closed by server\n");
        // 你可以选择在这里关闭套接字并退出程序,或者继续处理其他逻辑
    }
}

int main() {
    // 设置 SIGPIPE 信号处理器
    signal(SIGPIPE, sigpipe_handler);

    int client_fd;
    struct sockaddr_un client_addr;

    // 创建 UNIX 域套接字
    client_fd = socket(AF_UNIX, SOCK_STREAM, 0);
    if (client_fd == -1) {
        perror("socket failed");
        return 1;
    }

    // 初始化客户端地址
    client_addr.sun_family = AF_UNIX;
    strcpy(client_addr.sun_path, "/tmp/unix_socket");

    // 连接到服务器
    int ret = connect(client_fd, (struct sockaddr *)&client_addr, sizeof(client_addr));
    if (ret != 0) {
        fprintf(stderr, "Reconnect failed, exiting...\n");
        close(client_fd);
        return -1;
    }

    while (true)
    {
        char buffer[1024];
        printf("please write message: ");
        if (fgets(buffer, sizeof(buffer), stdin) != NULL)
        {
            // 去除可能的换行符
            size_t len = strlen(buffer);
            if (len > 0 && buffer[len - 1] == '\n') {
                buffer[len - 1] = '\0';
            }
            // 发送数据到服务器
            int bytes_sent = write(client_fd, buffer, strlen(buffer));
            if (bytes_sent == -1) {
                if (errno == EPIPE) {
                    fprintf(stderr, "Write error: Broken pipe, connection closed by server\n");
                    break;

                } else {
                    perror("write failed");
                    break;
                }
            }
            printf("send message: %s\n", buffer);

            // 接收回显消息
            memset(buffer, 0, 1024);
            int bytes_received = read(client_fd, buffer, 1024 - 1);
            if (bytes_received > 0) {
                printf("Received from server: %s\n", buffer);
            } else {
                perror("read failed");
            }
        }
        else
        {
            // 如果fgets返回NULL,可能是因为输入错误或者EOF,这里选择退出循环
            printf("write message error\n");
            break;
        }
    }
    close(client_fd);
    return 0;
}

2、服务端示例代码:

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

int main() {
    int server_fd, client_socket;
    struct sockaddr_un server_addr, client_addr;

    // 创建套接字
    server_fd = socket(AF_UNIX, SOCK_STREAM, 0);
    if (server_fd == -1) {
        perror("socket failed");
        exit(EXIT_FAILURE);
        return 1;
    }

    // 设置服务器地址
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sun_family = AF_UNIX;
    strcpy(server_addr.sun_path, "/tmp/unix_socket");
    unlink(server_addr.sun_path);

    // 绑定套接字
    if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
        perror("bind failed");
        exit(EXIT_FAILURE);
        return 1;
    }

    // 监听连接
    if (listen(server_fd, 5) == -1) {
        perror("listen failed");
        close(server_fd);
        return 1;
    }
    printf("Waiting for connection...\n");

    // 接受连接
    client_socket = accept(server_fd, NULL, NULL);
    if (client_socket == -1) {
        perror("accept failed");
        close(server_fd);
        return 1;
    }

    while (true)
    {
        char buffer[1024];
        printf("Waiting for read data...\n");
        int bytes_received = read(client_socket, buffer, sizeof(buffer)-1);
        if (bytes_received > 0) {
            buffer[bytes_received] = '\0';
            for (size_t i = 0; i < bytes_received; i++)
            {
                printf("Received data client: %c\n", buffer[i]);
            }

            printf("Received message from client: %s -----%d \n", buffer, bytes_received);
            // 发送回显消息
            // write(client_socket, buffer, bytes_received);
            if (write(client_socket, buffer, bytes_received) == -1) {
                perror("write failed");
                close(client_socket);
                break;
            }

        } else if (bytes_received == 0) {
            printf("Client disconnected.\n");
            break;
        } else {
            perror("read failed");
            break;
        }
        
    }

    close(server_fd);
    unlink(client_addr.sun_path);
    return 0;
}

参考文献:https://mp.weixin.qq.com/s/R6yu5IKothuHF0IRCDq_vQ


原文地址:https://blog.csdn.net/xiaofeilongyu/article/details/143716979

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!