Unix域套接字—基于文件的Socket通信

一.概述

在Linux中,.sock 文件通常是Unix域套接字(Unix Domain Socket)的一部分。

Unix域套接字是一种用于进程间通信的特殊类型的套接字,它不依赖于网络协议,而是使用文件系统作为通信的载体

Unix域套接字的特点:

  • 通信基于文件系统Unix域套接字通过在文件系统中创建一个特殊类型的文件(.sock 文件)来实现进程间通信。这个文件既可以在本地文件系统上,也可以在共享文件系统上。
  • 高性能:与基于网络的套接字相比,Unix域套接字通常具有更低的延迟和更高的吞吐量,因为它们不需要经过网络协议栈
  • 进程间通信:进程可以通过Unix域套接字相互发送消息,进行数据传输,实现进程间通信。

二.Unix套接字建立流程

图片[1]-Unix域套接字—基于文件的Socket通信-不念博客
整体流程图

Unix域套接字的创建通常涉及以下步骤:

  1. 创建套接字: 使用 socket() 系统调用创建一个Unix域套接字。
int socket(int domain, int type, int protocol);
  1. 绑定地址: 使用 bind() 系统调用将套接字与一个文件路径绑定,创建一个.sock文件。
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);`
  1. 监听连接(可选): 如果需要,可以使用 listen() 系统调用监听连接。
int listen(int sockfd, int backlog);
  1. 接受连接(可选): 使用 accept() 系统调用接受客户端的连接请求。
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
  1. 进行通信: 使用 send() 和 recv() 等系统调用进行进程间通信。
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);
  1. 关闭套接字: 使用 close() 关闭Unix域套接字。
int close(int sockfd);

7.销毁文件

 // 删除创建的文件
    unlink(SOCKET_PATH);

三.综合示例

server.c文件

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

#define SOCKET_PATH "example.sock"
#define BUFFER_SIZE 1024

int main() {
    int server_socket, client_socket;
    struct sockaddr_un server_address, client_address;
    socklen_t client_address_len = sizeof(client_address);
    char buffer[BUFFER_SIZE];

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

    // 设置服务器地址结构
    memset(&server_address, 0, sizeof(server_address));
    server_address.sun_family = AF_UNIX;
    strncpy(server_address.sun_path, SOCKET_PATH, sizeof(server_address.sun_path) - 1);

    // 绑定地址
    if (bind(server_socket, (struct sockaddr*)&server_address, sizeof(server_address)) == -1) {
        perror("Bind failed");
        exit(EXIT_FAILURE);
    }

    // 监听连接
    if (listen(server_socket, 5) == -1) {
        perror("Listen failed");
        exit(EXIT_FAILURE);
    }

    printf("等待客户端连接...\n");

    // 接受连接
    client_socket = accept(server_socket, (struct sockaddr*)&client_address, &client_address_len);
    if (client_socket == -1) {
        perror("Accept failed");
        exit(EXIT_FAILURE);
    }

    printf("客户端已连接\n");

    // 接收数据
    ssize_t bytes_received = recv(client_socket, buffer, sizeof(buffer), 0);
    if (bytes_received == -1) {
        perror("Receive failed");
        exit(EXIT_FAILURE);
    }

    buffer[bytes_received] = '\0'; // 添加字符串结束符
    printf("接收到的数据: %s\n", buffer);

    // 发送响应
    const char* response = "收到消息";
    if (send(client_socket, response, strlen(response), 0) == -1) {
        perror("Send failed");
        exit(EXIT_FAILURE);
    }

    // 关闭套接字
    close(client_socket);
    close(server_socket);

    // 删除创建的文件
    unlink(SOCKET_PATH);

    return 0;
}

client.c文件:

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

#define SOCKET_PATH "example.sock"
#define BUFFER_SIZE 1024

int main() {
    int client_socket;
    struct sockaddr_un server_address;
    char buffer[BUFFER_SIZE];
    ssize_t bytes_received;

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

    // 设置服务器地址结构
    memset(&server_address, 0, sizeof(server_address));
    server_address.sun_family = AF_UNIX;
    strncpy(server_address.sun_path, SOCKET_PATH, sizeof(server_address.sun_path) - 1);

    // 连接服务器
    if (connect(client_socket, (struct sockaddr*)&server_address, sizeof(server_address)) == -1) {
        perror("Connection failed");
        exit(EXIT_FAILURE);
    }

    // 发送数据
    const char* message = "Hello, Server!";
    if (send(client_socket, message, strlen(message), 0) == -1) {
        perror("Send failed");
        exit(EXIT_FAILURE);
    }

    printf("发送消息: %s\n", message);

    // 接收响应
    bytes_received = recv(client_socket, buffer, sizeof(buffer), 0);
    if (bytes_received == -1) {
        perror("Receive failed");
        exit(EXIT_FAILURE);
    }

    buffer[bytes_received] = '\0'; // 添加字符串结束符
    printf("服务器响应: %s\n", buffer);

    // 关闭套接字
    close(client_socket);

    return 0;
}

效果展示:

图片[2]-Unix域套接字—基于文件的Socket通信-不念博客
client/server

大家可以根据实际的需求,对这个Demo进行修改,通过这个例子我们可以基本认识到通过文件建立Unix域套接字的通信过程。

© 版权声明
THE END