基于抽象命名空间的本地套接字bind问题探究

基于抽象命名空间的本地套接字,bind在内核对应的函数是unix_bind_abstract,会根据用户态传的 struct sockaddr_un的内容插入hash表
如果父进程绑定了基于抽象空间的本地套接字,然后fork子进程,后续父进程退出,父进程退出时不会调用unix_release从hash表删除原来的抽象命名空间。在原来的子进程未退出的情况下,重新绑定抽象命名空间将会失败。

//// 父进程未退出
anlan@anlan:/proc/3439/fd$ netstat -anp | grep 1905
(并非所有进程都能被检测到,所有非本用户的进程信息将不会显示,如果想看到所有信息,则必须切换到 root 用户)
unix  2      [ ACC ]     流        LISTENING     68691    3659/main            @./1905_daemon@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//// 父进程退出
anlan@anlan:/proc/3439/fd$ netstat -anp | grep 1905
(并非所有进程都能被检测到,所有非本用户的进程信息将不会显示,如果想看到所有信息,则必须切换到 root 用户)
unix  2      [ ACC ]     流        LISTENING     68691    3669/./child         @./1905_daemon@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

查看child进程的文件描述符信息
anlan@anlan:/proc/3669/fd$ ls -l
总用量 0
lr-x------ 1 anlan anlan 64 5月  23 15:51 0 -> /dev/null
lrwx------ 1 anlan anlan 64 5月  23 15:51 1 -> /dev/pts/2
lr-x------ 1 anlan anlan 64 5月  23 15:51 103 -> /usr/share/code/v8_context_snapshot.bin
lrwx------ 1 anlan anlan 64 5月  23 15:51 2 -> /dev/pts/2
lrwx------ 1 anlan anlan 64 5月  23 15:51 3 -> 'socket:[68691]'
l-wx------ 1 anlan anlan 64 5月  23 15:51 37 -> /home/anlan/.config/Code/logs/20250523T151626/ptyhost.log
lrwx------ 1 anlan anlan 64 5月  23 15:51 38 -> /dev/ptmx
lr-x------ 1 anlan anlan 64 5月  23 15:51 39 -> /usr/share/code/resources/app/node_modules.asar
//// 再次启动main进程
anlan@anlan:~/桌面/unix_bind$ ./main
bind: Address already in use

除非kill掉child进程否则main进程绑定socket将不会成功
// main.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>

#define SOCKET_PATH "./daemon"
#define BUFFER_SIZE 1024

int main() {
    int server_fd, client_fd;
    struct sockaddr_un server_addr, client_addr;
    socklen_t client_len;
    char buffer[BUFFER_SIZE];
    int bytes_read;

    // Remove the socket file if it already exists

    // Create the socket
    server_fd = socket(AF_UNIX, SOCK_STREAM, 0);
    if (server_fd == -1) {
        perror("socket");
        exit(EXIT_FAILURE);
    }

    // Configure server address
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sun_family = AF_UNIX;
    snprintf(server_addr.sun_path + 1, sizeof(server_addr.sun_path) - 1, "%s", SOCKET_PATH);

    // Bind the socket to the address
    if (bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) {
        perror("bind");
        close(server_fd);
        exit(EXIT_FAILURE);
    }

    // Listen for incoming connections
    if (listen(server_fd, 5) == -1) {
        perror("listen");
        close(server_fd);
        exit(EXIT_FAILURE);
    }

    printf("Server is listening on %s...\n", SOCKET_PATH);

    system("./child &");


    while (1) {
        // Accept a client connection
        client_len = sizeof(client_addr);
        client_fd = accept(server_fd, (struct sockaddr*)&client_addr, &client_len);
        if (client_fd == -1) {
            perror("accept");
            continue;
        }

        printf("Client connected\n");

        // Handle client communication
        while ((bytes_read = read(client_fd, buffer, sizeof(buffer))) > 0) {
            printf("Received: %.*s", bytes_read, buffer);

            // Echo back to client
            if (write(client_fd, buffer, bytes_read) != bytes_read) {
                perror("write");
                break;
            }
        }

        if (bytes_read == -1) {
            perror("read");
        }

        printf("Client disconnected\n");
        close(client_fd);
    }

    // Clean up (this part won't be reached in this example)
    close(server_fd);
    return 0;
}
// child.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(int argc, const char *argv[])
{
    while (1)
    {
        sleep(1);
    }
    return 0;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容