linux

Linux进程如何共享文件描述符

小樊
45
2025-12-15 22:36:17
栏目: 智能运维

在Linux中,进程可以通过多种方式共享文件描述符。以下是一些常见的方法:

1. fork() 系统调用

当一个进程调用 fork() 创建子进程时,子进程会继承父进程的所有文件描述符。这意味着子进程和父进程将共享相同的文件描述符表,指向相同的文件表项。

#include <stdio.h>
#include <unistd.h>

int main() {
    int fd = open("example.txt", O_RDONLY);
    if (fd == -1) {
        perror("open");
        return 1;
    }

    pid_t pid = fork();
    if (pid == -1) {
        perror("fork");
        close(fd);
        return 1;
    } else if (pid == 0) {
        // 子进程
        printf("Child process: fd = %d\n", fd);
        close(fd); // 子进程关闭文件描述符
    } else {
        // 父进程
        printf("Parent process: fd = %d\n", fd);
        close(fd); // 父进程关闭文件描述符
    }

    return 0;
}

2. dup()dup2() 系统调用

dup()dup2() 系统调用可以用于复制文件描述符。dup() 返回一个新的文件描述符,指向与现有文件描述符相同的文件表项。dup2() 可以将一个文件描述符重定向到另一个文件描述符。

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

int main() {
    int fd = open("example.txt", O_RDONLY);
    if (fd == -1) {
        perror("open");
        return 1;
    }

    int fd2 = dup(fd);
    if (fd2 == -1) {
        perror("dup");
        close(fd);
        return 1;
    }

    printf("Original fd: %d\n", fd);
    printf("Duplicated fd: %d\n", fd2);

    close(fd); // 关闭原始文件描述符
    close(fd2); // 关闭复制的文件描述符

    return 0;
}

3. socketpair() 系统调用

socketpair() 系统调用可以创建一对相互连接的套接字描述符,这些套接字描述符可以在进程间共享。

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

int main() {
    int sockets[2];
    if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) == -1) {
        perror("socketpair");
        return 1;
    }

    printf("Socket 1: %d\n", sockets[0]);
    printf("Socket 2: %d\n", sockets[1]);

    close(sockets[0]);
    close(sockets[1]);

    return 0;
}

4. pipe() 系统调用

pipe() 系统调用可以创建一个管道,管道的两个端点可以作为文件描述符在进程间共享。

#include <stdio.h>
#include <unistd.h>

int main() {
    int pipefd[2];
    if (pipe(pipefd) == -1) {
        perror("pipe");
        return 1;
    }

    printf("Read end of pipe: %d\n", pipefd[0]);
    printf("Write end of pipe: %d\n", pipefd[1]);

    close(pipefd[0]);
    close(pipefd[1]);

    return 0;
}

5. sendmsg()recvmsg() 系统调用

sendmsg()recvmsg() 系统调用可以用于在进程间传递文件描述符。

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

int main() {
    int sockets[2];
    if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) == -1) {
        perror("socketpair");
        return 1;
    }

    char buf[] = "Hello, World!";
    struct msghdr msg;
    struct iovec iov;
    char cmsgbuf[CMSG_SPACE(sizeof(int))];
    struct cmsghdr *cmsg;

    iov.iov_base = buf;
    iov.iov_len = strlen(buf);

    msg.msg_name = NULL;
    msg.msg_namelen = 0;
    msg.msg_iov = &iov;
    msg.msg_iovlen = 1;
    msg.msg_control = cmsgbuf;
    msg.msg_controllen = sizeof(cmsgbuf);

    cmsg = CMSG_FIRSTHDR(&msg);
    cmsg->cmsg_level = SOL_SOCKET;
    cmsg->cmsg_type = SCM_RIGHTS;
    cmsg->cmsg_len = CMSG_LEN(sizeof(int));

    *(int *)CMSG_DATA(cmsg) = sockets[1];

    if (sendmsg(sockets[0], &msg, 0) == -1) {
        perror("sendmsg");
        close(sockets[0]);
        close(sockets[1]);
        return 1;
    }

    close(sockets[0]);

    char recvbuf[1024];
    iov.iov_base = recvbuf;
    iov.iov_len = sizeof(recvbuf);

    msg.msg_name = NULL;
    msg.msg_namelen = 0;
    msg.msg_iov = &iov;
    msg.msg_iovlen = 1;
    msg.msg_control = NULL;
    msg.msg_controllen = 0;

    if (recvmsg(sockets[1], &msg, 0) == -1) {
        perror("recvmsg");
        close(sockets[1]);
        return 1;
    }

    printf("Received message: %s\n", recvbuf);

    close(sockets[1]);

    return 0;
}

这些方法可以帮助你在Linux进程间共享文件描述符。选择哪种方法取决于你的具体需求和应用场景。

0
看了该问题的人还看了