zoukankan      html  css  js  c++  java
  • 在进程间传递文件描述符

      由于fork调用之后,父进程中打开的文件描述符在子进程中仍然保持打开,所以文件描述符可以很方便地从父进程传递到子进程。需要注意的是,传递一个文件描述符并不是传递一个文件描述符的值,而是要在接收进程中创建一个新的文件描述符,并且该文件描述符和发送进程中被传递的文件描述符指向内核中相同的文件表项。
      在Linux下,我们可以利用UNIX城socket在进程间传递特殊的辅助数据,以实现文件描述符的传递,它在子进程中打开一个文件描述符,然后将它传递给父进程,父进程则通过读取该文件描述符来获得文件的内容。

    #include<sys/socket.h>
    #include<sys/param.h>
    #include<fcntl.h>
    #include<stdio.h>
    #include<unistd.h>
    #include<stdlib.h>
    #include<assert.h>
    #include<string.h>
    /*
    struct cmsghdr *CMSG_FIRSTHDR(struct msghdr *msgh);
    struct cmsghdr *CMSG_NXTHDR(struct msghdr *msgh,struct cmsghdr *cmsg);
    size_t CMSG_ALIGN(size_t length);
    size_t CMSG_SPACE(size_t length);
    size_t CMSG_LEN(size_t length);
    unsigned char* CMSG_DATA(struct cmsghdr *cmsg);
    struct cmsghdr{
            socklen_t cmsg_len;
            int cmsg_level;
            int cmsg_type;
    };
    */
    static const int CONTROL_LEN = CMSG_LEN(sizeof(int));
    /*发送文件描述符,fd参数是用来传递信息的UNIX域的socket,fd_to_send参数是待发送的文件描述符*/
     
    void send_fd(int fd,int fd_to_send)
    {
        struct iovec iov[1];
        struct msghdr msg;
        char buf[0];
     
        iov[0].iov_base = buf;
        iov[1].iov_len = 1;
        msg.msg_name = NULL;
        msg.msg_namelen = 0;
        msg.msg_iov  = iov;
        msg.msg_iovlen = 1;
     
        cmsghdr cm;
        cm.cmsg_len = CONTROL_LEN;
        cm.cmsg_level = SOL_SOCKET;
        cm.cmsg_type = SCM_RIGHTS;
        *(int *)CMSG_DATA(& cm) = fd_to_send;
        msg.msg_control = &cm;//设置辅助数据
        msg.msg_controllen = CONTROL_LEN;
     
        sendmsg(fd,&msg,0);
    }
    int recv_fd(int fd)
    {
        struct iovec iov[1];
        struct msghdr msg;
        char buf[0];
     
        iov[0].iov_base = buf;
        iov[1].iov_len = 1;
        msg.msg_name = NULL;
        msg.msg_namelen = 0;
        msg.msg_iov  = iov;
        msg.msg_iovlen = 1;
     
        cmsghdr cm;
        msg.msg_control = &cm;
        msg.msg_controllen = CONTROL_LEN;
     
        recvmsg( fd,&msg,0);
     
        int fd_to_read = *(int *)CMSG_DATA(&cm);
        return fd_to_read;
    }
    int main()
    {
            int pipefd[2];
            int fd_to_pass = 0;//文件描述符的传递值
            /*创建父,子进程间的管道,文件描述符 pipefd[0]和pipefd[1]*/
     
            int ret = socketpair( PF_UNIX,SOCK_DGRAM,0,pipefd);//管道函数
            assert(ret != -1);
     
            pid_t pid = fork();
            assert(pid >= 0);
     
            if(pid == 0)//子进程
            {
                    close(pipefd[0]);//?????
                    fd_to_pass = open("text.txt",O_RDWR,0666);
                    /*子进程通过管道将文件描述符发送到父进程。如果文件text打开失败则子进程将标准输入文件描述符发送到父进程*/
                    send_fd( pipefd[1],(fd_to_pass > 0)?fd_to_pass:0);
                    close(fd_to_pass);
                    exit(0);
            }
     
            close(pipefd[1]);
            fd_to_pass = recv_fd(pipefd[0]);//父进程从管道接收目标文件描述符
            char buff[128];
            memset(buff,0,sizeof(buff));
            read(fd_to_pass,buff,127);//读目标文件描述符,以验证其有效性
            printf("I Got fd: %d and Data: %s
    ",fd_to_pass,buff);
            close(fd_to_pass);
            return 0;
    }
  • 相关阅读:
    在 macOS High Sierra 10.13 搭建 PHP 开发环境
    给你的网站免费配置上 HTTPS 证书
    将 MacOS 默认的 PHP 版本升级到 7.*
    System.Data.SqlClient.SqlException: 'Incorrect syntax near 'OFFSET'.
    IIS7/8 HTTP Error 500.19 错误 0x80070021 错误代码:0x8007000d
    http error 502.5
    信用卡逾期了怎么办 ?逾期记录“修复”的两大原则
    APP多开教程
    lua调用不同lua文件中的函数
    Lua 用指定字符或字符串分割输入字符串,返回包含分割结果的数组
  • 原文地址:https://www.cnblogs.com/tianzeng/p/10792563.html
Copyright © 2011-2022 走看看