描述符传递

前端之家收集整理的这篇文章主要介绍了描述符传递前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

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),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,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,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,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]),"",fd)) < 0) {
        exit(n);
    }
    exit(0);
}

猜你在找的Bash相关文章