Linux学习之路Linux读书笔记

APUE读书笔记-17高级进程通信(10)

2020-08-14  本文已影响0人  QuietHeart

使用streams pipes进行文件符号传输

文件描述符号用两个ioctl命令:I_SENDFD和I_RECVFD,通过streams pipes被交换。

对于streams pipes的send_fd函数

发送一个文件描述符号的时候我们设置ioctl的第三个参数为实际的文件描述符号。代码如下:

#include "apue.h"
#include <stropts.h>

/*
 * Pass a file descriptor to another process.
 * If fd<0, then -fd is sent back instead as the error status.
 */
int send_fd(int fd, int fd_to_send)
{
    char    buf[2];     /* send_fd()/recv_fd() 2-byte protocol */

    buf[0] = 0;         /* null byte flag to recv_fd() */
    if (fd_to_send < 0) {
        buf[1] = -fd_to_send;   /* nonzero status means error */
        if (buf[1] == 0)
            buf[1] = 1; /* -256, etc. would screw up protocol */
    } else {
        buf[1] = 0;     /* zero status means OK */
    }

    if (write(fd, buf, 2) != 2)
        return(-1);
    if (fd_to_send >= 0)
        if (ioctl(fd, I_SENDFD, fd_to_send) < 0)
            return(-1);
    return(0);
}

当我们接收一个文件描述符号的时候,ioctl的第3个参数是一个如下strrecvfd结构的指针:

struct strrecvfd {
        int    fd;       /* new descriptor */
        uid_t  uid;      /* effective user ID of sender */
        gid_t  gid;      /* effective group ID of sender */
        char   fill[8];
};

streams pipe的recv_fd函数

recv_fd函数从streams pipe中读取信息,直到2字节协议的第一个字节被接收(null字节)。当我们通过I_RECVFD的ioctl命令请求的时候,流头部的读取队列的下一条消息必须是来自I_SENDFD调用的文件描述符号,或者我们获得一个错误。函数代码如下所示:

#include "apue.h"
#include <stropts.h>
/*
 * Receive a file descriptor from another process (a server).
 * In addition, any data received from the server is passed
 * to (*userfunc)(STDERR_FILENO, buf, nbytes). We have a
 * 2-byte protocol for receiving the fd from send_fd().
 */
int recv_fd(int fd, ssize_t (*userfunc)(int, const void *, size_t))
{
    int                 newfd, nread, flag, status;
    char                *ptr;
    char                buf[MAXLINE];
    struct strbuf       dat;
    struct strrecvfd    recvfd;

    status = -1;
    for ( ; ; ) {
        dat.buf = buf;
        dat.maxlen = MAXLINE;
        flag = 0;
        if (getmsg(fd, NULL, &dat, &flag) < 0)
            err_sys("getmsg error");
        nread = dat.len;
        if (nread == 0) {
            err_ret("connection closed by server");
            return(-1);
        }
        /*
         * See if this is the final data with null & status.
         * Null must be next to last byte of buffer, status
         * byte is last byte. Zero status means there must
         * be a file descriptor to receive.
         */
        for (ptr = buf; ptr < &buf[nread]; ) {
            if (*ptr++ == 0) {
                if (ptr != &buf[nread-1])
                    err_dump("message format error");
                 status = *ptr & 0xFF;   /* prevent sign extension */
                 if (status == 0) {
                     if (ioctl(fd, I_RECVFD, &recvfd) < 0)
                         return(-1);
                     newfd = recvfd.fd;  /* new descriptor */
                 } else {
                     newfd = -status;
                 }
                 nread -= 2;
            }
        }
        if (nread > 0)
            if ((*userfunc)(STDERR_FILENO, buf, nread) != nread)
                 return(-1);
        if (status >= 0)    /* final data has arrived */
            return(newfd);  /* descriptor, or -status */
    }
}
上一篇 下一篇

猜你喜欢

热点阅读