首页 > 代码库 > 在父子进程间用管道传递文件描述符

在父子进程间用管道传递文件描述符

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>

#define ERR_EXIT(m)     do {         perror(m);        exit(EXIT_FAILURE);    }while(0)

void send_fd(int sock_fd, int fd);
int recv_fd(const int sock_fd);

int main(int argc, const char *argv[])
{
    int fds[2];
    socketpair(PF_UNIX, SOCK_STREAM, 0, fds);
    pid_t pid;
    pid = fork();
    if(pid < 0)
        ERR_EXIT("fork");
    else if(pid == 0){
        close(fds[1]);
        int fd = open("test.txt", O_RDONLY);
        if(fd == -1)
            ERR_EXIT("open");
        send_fd(fds[0], fd);
    }else{
        sleep(1);
        close(fds[0]);
        int fd = recv_fd(fds[1]);
        char buffer[1024] = {0};
        read(fd, buffer, 1024);
        printf("Recv msg: %s\n", buffer);
    }
    return 0;
}

void send_fd(int sock_fd, int fd)
{
        int ret;
        struct msghdr msg;
        struct cmsghdr *p_cmsg;
        struct iovec vec;
        char cmsgbuf[CMSG_SPACE(sizeof(fd))];
        int *p_fds;
        char sendchar = 0;
        msg.msg_control = cmsgbuf;
        msg.msg_controllen = sizeof(cmsgbuf);
        p_cmsg = CMSG_FIRSTHDR(&msg);
        p_cmsg->cmsg_level = SOL_SOCKET;
        p_cmsg->cmsg_type = SCM_RIGHTS;
        p_cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
        p_fds = (int*)CMSG_DATA(p_cmsg);
        *p_fds = fd;

        msg.msg_name = NULL;
        msg.msg_namelen = 0;
        msg.msg_iov = &vec;
        msg.msg_iovlen = 1;
        msg.msg_flags = 0;

        vec.iov_base = &sendchar;
        vec.iov_len = sizeof(sendchar);
        ret = sendmsg(sock_fd, &msg, 0);
        if (ret != 1)
                ERR_EXIT("sendmsg");
}

int recv_fd(const int sock_fd)
{
        int ret;
        struct msghdr msg;
        char recvchar;
        struct iovec vec;
        int recv_fd;
        char cmsgbuf[CMSG_SPACE(sizeof(recv_fd))];
        struct cmsghdr *p_cmsg;
        int *p_fd;
        vec.iov_base = &recvchar;
        vec.iov_len = sizeof(recvchar);
        msg.msg_name = NULL;
        msg.msg_namelen = 0;
        msg.msg_iov = &vec;
        msg.msg_iovlen = 1;
        msg.msg_control = cmsgbuf;
        msg.msg_controllen = sizeof(cmsgbuf);
        msg.msg_flags = 0;

        p_fd = (int*)CMSG_DATA(CMSG_FIRSTHDR(&msg));
        *p_fd = -1;  
        ret = recvmsg(sock_fd, &msg, 0);
        if (ret != 1)
                ERR_EXIT("recvmsg");

        p_cmsg = CMSG_FIRSTHDR(&msg);
        if (p_cmsg == NULL)
                ERR_EXIT("no passed fd");


        p_fd = (int*)CMSG_DATA(p_cmsg);
        recv_fd = *p_fd;
        if (recv_fd == -1)
                ERR_EXIT("no passed fd");

        return recv_fd;
}

在父子进程间用管道传递文件描述符