描述符传递

Example.No.1:
通过socketpair打开两个连接起来的Unix套接字,一个用于进程本身读取内容,并输出到进程本身的标准输出,另一个则用于子进程传递通过Unix套接字发送excel的一个进程打开的文件描述符,通过sendmsg的辅助数据传递

进程本身代码:

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

#define BUFSIZE 4096


int read_fd(int fd,void* ptr,size_t nbytes,int* recvfd ) {
    struct msghdr msg;
    struct iovec iov[1];
    ssize_t n;
    union {
        struct cmsghdr cm;
        char control[CMSG_SPACE(sizeof(int))];
    }control_un;

    msg.msg_control = control_un.control;
    msg.msg_controllen = sizeof(control_un.control);
    msg.msg_name = NULL;
    msg.msg_namelen = 0;
    iov[0].iov_base = ptr;
    iov[0].iov_len = nbytes;
    msg.msg_iov = iov;
    msg.msg_iovlen = 1;
    if ((n = recvmsg(fd,&msg,0)) <= 0) {
        return n;
    }
    struct cmsghdr* cmptr;
    if ((cmptr = CMSG_FIRSTHDR(&msg)) != NULL && cmptr->cmsg_len == CMSG_LEN(sizeof(int))) {
        if (cmptr->cmsg_level != SOL_SOCKET) {
            printf("control level != SOL_SOCKET\n");
            exit(1);
        }

        if (cmptr->cmsg_type != SCM_RIGHTS) {
            printf("control level != SCM_RIGHTS\n");
            exit(1);
        }
        *recvfd = *(int*)CMSG_DATA(cmptr);
    }else {
        *recvfd = -1;
    }
}
int my_open(char* pathname,int mode) {
    int fd,sockfd[2],status;
    char c;
    if (socketpair(AF_LOCAL,SOCK_STREAM,0,sockfd) < 0) {
        printf("setsockpair error: %s\n",strerror(errno));
        exit(1);
    }
    int childpid;
    if ((childpid = fork()) < 0) {
        printf("fork error: %s\n",strerror(errno)); 
        exit(1);
    }else if (childpid == 0) {
        char argsockfd[10],argmode[10];
        snprintf(argsockfd,sizeof(argsockfd),"%d",sockfd[1]);
        snprintf(argmode,sizeof(argmode),"%d",mode);
        execl("./openfile","openfile",argsockfd,pathname,argmode,(char*)NULL);
    }
    close(sockfd[1]);
    if (waitpid(childpid,&status,0) < 0) {
        printf("waitpid error: %s\n",strerror(errno));
        exit(1);
    }
    if (WIFEXITED(status) == 0) {
        printf("child process did not terminate\n");
        exit(1);
    }

    if ((status = WEXITSTATUS(status)) == 0) {
        if (read_fd(sockfd[0],&c,1,&fd) < 0) {
            printf("read_fd error\n");
            exit(1);
        }
    }else {
        errno = status;
        fd = -1;
    }
    close(sockfd[0]);
    return fd;
}
int main(int argc,char** argv) {
    if (argc != 2) {
        printf("please add <pathname>\n");
        exit(1);
    }

    int fd;
    if ((fd = my_open(argv[1],O_RDONLY)) < 0) {
        printf("can't open %s\n",argv[1]);
        exit(1);
    }
    char buf[BUFSIZE];
    int n;
    while ((n = read(fd,buf,BUFSIZE)) > 0) {
        if (write(STDOUT_FILENO,buf,n) != n) {
            printf("write error: %s\n",strerror(errno));
            exit(1);
        }
    }
    return 0;
}

openfile进程代码:

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

int write_fd(int fd,void* ptr,size_t nbytes,int sendfd) {
    struct msghdr msg;
    struct iovec iov[1];

    union {
        struct cmsghdr cmsg;
        char controls[CMSG_SPACE(sizeof(int))];
    }control_un;

    msg.msg_name = NULL;
    msg.msg_namelen = 0;
    msg.msg_control = control_un.controls;
    msg.msg_controllen = sizeof(control_un.controls);
    struct cmsghdr* cmptr;
    cmptr = CMSG_FIRSTHDR(&msg);
    cmptr->cmsg_len = CMSG_LEN(sizeof(int));
    cmptr->cmsg_level = SOL_SOCKET;
    cmptr->cmsg_type = SCM_RIGHTS;
    *(int*)(CMSG_DATA(cmptr)) = sendfd;
    iov[0].iov_base = ptr;
    iov[0].iov_len = nbytes;
    msg.msg_iov = iov;
    msg.msg_iovlen = 1;
    return sendmsg(fd,&msg,0);
}

int main(int argc,char** argv) {
    if (argc != 4) {
        printf("please check your input-arguments\n");
        exit(1);
    }

    int fd;
    if ((fd = open(argv[2],atoi(argv[3]))) < 0) {
        printf("open %s fail: error reason: %s\n",argv[2],strerror(errno));
        exit(1);
    }

    int n;
    if ((n = write_fd(atoi(argv[1]),"",1,fd)) < 0) {
        exit(n);
    }
    exit(0);
}

这里写图片描述

猜你喜欢

转载自blog.csdn.net/rgbmarco/article/details/79368312