进程间传递文件描述符的方法

UNP讲述了三种传递描述符的方法:

1.使用ioctl

2.如果是父子关系进程用socketpair

3.没关系则使用unix socket

 

这里介绍一下第三种,因为相对复杂繁琐:

  UNP里讲述了这个步骤:

  1.创建unix stream socket,其中要有一个是bind且在listen的。

  2.使用sendmsg与recvmsg接口传送描述符

  3.需要注意的是相关的工具宏和struct.具体翻阅14.5节.

下面我自己写的两个示例代码,图一接收文件描述符并输出hello来验证,图二是要一个临时文件作为参数传入,并发送该文件的套接字给图一的进程.值得注意的是,在发送时,该文件描述符的引用计数会增加,因此关闭进程2并不会导致进程1使用此描述符.

extern "C"
{
#include 
}

int main(int argc, char **argv)
{
    sockaddr_un seraddr;
    bzero(&seraddr, sizeof(seraddr));
    seraddr.sun_family = AF_UNIX;
    strcpy(seraddr.sun_path, UNIXSTR_PATH);
    int lisfd = socket(AF_UNIX, SOCK_STREAM, 0);
    int on = 1;
    unlink(UNIXSTR_PATH);
    Bind(lisfd, (SA *)&seraddr, sizeof(seraddr));
    Listen(lisfd, LISTENQ);
    sockaddr_un cliaddr;
    socklen_t addrlen;
    int connfd = Accept(lisfd, (SA *)&cliaddr, &addrlen);
    msghdr msg;
    iovec iov;
    msg.msg_name = NULL;
    msg.msg_namelen = 0;
    int tmp;
    iov.iov_base = &tmp;
    iov.iov_len = sizeof(int);
    msg.msg_iov = &iov;
    msg.msg_iovlen = 1;
    union {
        cmsghdr cm;
        char control[CMSG_SPACE(sizeof(int))];
    } control_un;
    msg.msg_control = control_un.control;
    msg.msg_controllen = sizeof(control_un.control);
    if (recvmsg(connfd, &msg, 0) < 0)
    {
        perror("recvmsg");
    }
    int recvfd = -1;
    auto cmptr = CMSG_FIRSTHDR(&msg);
    if (cmptr == NULL)
    {
        perror("CMSG");
    }
    if (cmptr->cmsg_type != SCM_RIGHTS)
    {
        perror("type");
    }
    recvfd = *((int *)CMSG_DATA(cmptr));
    char buf[] = "hello";
    printf("the fd: %d  ", recvfd);
    Write(recvfd, buf, strlen(buf) + 1);
    exit(0);
}

 

extern "C"
{
#include 
}

int main(int argc, char **argv)
{
    int sndfd = open(argv[1], O_RDWR | O_TRUNC | O_CREAT);
    printf("the fd: %d", sndfd);
    sockaddr_un seraddr;
    bzero(&seraddr, sizeof(seraddr));
    seraddr.sun_family = AF_UNIX;
    strcpy(seraddr.sun_path, UNIXSTR_PATH);
    int connfd = Socket(AF_UNIX, SOCK_STREAM, 0);
    Connect(connfd, (SA *)&seraddr, sizeof(seraddr));
    msghdr msg;
    msg.msg_name = NULL;
    msg.msg_namelen = 0;
    iovec iov;
    iov.iov_base = &sndfd;
    iov.iov_len = sizeof(sndfd);
    msg.msg_flags = 0;
    union {
        cmsghdr cm;
        char pad[CMSG_SPACE(sizeof(int))];
    } control;
    msg.msg_control = control.pad;
    msg.msg_controllen = sizeof(control.pad);
    msg.msg_flags = 0;
    msg.msg_iov = &iov;
    msg.msg_iovlen = 1;
    auto cmsgptr = CMSG_FIRSTHDR(&msg);
    cmsgptr->cmsg_len = CMSG_LEN(sizeof(int));
    cmsgptr->cmsg_level = SOL_SOCKET;
    cmsgptr->cmsg_type = SCM_RIGHTS;
    *(int *)CMSG_DATA(cmsgptr) = sndfd;
    sendmsg(connfd, &msg, 0);
    exit(0);
}

 

你可能感兴趣的:(进程间传递文件描述符的方法)