Linux

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

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

客户端

open.h头文件

首先我们定义头文件,包含一些标准头文件和函数的声明:

#include "apue.h"
#include <errno.h>
#define CL_OPEN "open"        /* client's request for server */
int     csopen(char *, int);

客户进程的main函数(版本1)

main函数就是一个循环,从标准输入读取路径,然后将文件拷贝到标准输出。这个函数调用csopen来连接打开文件的服务进程,并且返回一个打开的文件描述符号。

#include    "open.h"
#include    <fcntl.h>
#define BUFFSIZE    8192
int main(int argc, char *argv[])
{
    int     n, fd;
    char    buf[BUFFSIZE], line[MAXLINE];

    /* read filename to cat from stdin */
    while (fgets(line, MAXLINE, stdin) != NULL) {
        if (line[strlen(line) - 1] == '\n')
            line[strlen(line) - 1] = 0; /* replace newline with null */

        /* open the file */
        if ((fd = csopen(line, O_RDONLY)) < 0)
            continue;   /* csopen() prints error from server */

        /* and cat to stdout */
        while ((n = read(fd, buf, BUFFSIZE)) > 0)
            if (write(STDOUT_FILENO, buf, n) != n)
                err_sys("write error");
        if (n < 0)
            err_sys("read error");
        close(fd);
    }

    exit(0);
}

csopen函数(版本1)

创建了s-pipe管道之后,函数csopen调用fork和exec服务进程。

#include    "open.h"
#include    <sys/uio.h>     /* struct iovec */
/*
 * Open the file by sending the "name" and "oflag" to the
 * connection server and reading a file descriptor back.
 */
int csopen(char *name, int oflag)
{
    pid_t           pid;
    int             len;
    char            buf[10];
    struct iovec    iov[3];
    static int      fd[2] = { -1, -1 };

    if (fd[0] < 0) {    /* fork/exec our open server first time */
        if (s_pipe(fd) < 0)
            err_sys("s_pipe error");
        if ((pid = fork()) < 0) {
            err_sys("fork error");
        } else if (pid == 0) {      /* child */
            close(fd[0]);
            if (fd[1] != STDIN_FILENO &&
              dup2(fd[1], STDIN_FILENO) != STDIN_FILENO)
                err_sys("dup2 error to stdin");
            if (fd[1] != STDOUT_FILENO &&
              dup2(fd[1], STDOUT_FILENO) != STDOUT_FILENO)
                err_sys("dup2 error to stdout");
            if (execl("./opend", "opend", (char *)0) < 0)
                err_sys("execl error");
        }
        close(fd[1]);               /* parent */
    }
    sprintf(buf, " %d", oflag);     /* oflag to ascii */
    iov[0].iov_base = CL_OPEN " ";      /* string concatenation */
    iov[0].iov_len  = strlen(CL_OPEN) + 1;
    iov[1].iov_base = name;
    iov[1].iov_len  = strlen(name);
    iov[2].iov_base = buf;
    iov[2].iov_len  = strlen(buf) + 1;  /* +1 for null at end of buf */
    len = iov[0].iov_len + iov[1].iov_len + iov[2].iov_len;
    if (writev(fd[0], &iov[0], 3) != len)
        err_sys("writev error");
    /* read descriptor, returned errors handled by write() */
    return(recv_fd(fd[0], write));
}

子进程关闭管道的一端,父进程关闭另外一端。exec服务进程之前,子进程首先将管道的没有关闭的那端dup到其标准输入和标准输出中。(另外一个可以选择的就是将文件描述符号 fd[1] 的ASCII表示作为一个参数传递给服务进程)

父进程给服务进程发送包含路径和open模式的请求。最后,父进程调用recv_fd来返回文件描述符号或者错误。如果错误被服务进程返回,那么向标准错误输出写相关的信息。

上一篇下一篇

猜你喜欢

热点阅读