美文网首页LinuxLinux学习之路
APUE读书笔记-17高级进程通信(14)

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

作者: QuietHeart | 来源:发表于2020-08-19 15:23 被阅读0次

    服务端

    现在我们来查看一下打开的服务进程。下面就是客户进程exec的opend程序的代码。

    opend.h头文件,版本1

    首先我们需要有一个opend.h头文件,这个头文件包含一些标准的头文件以及声明一些全局变量和函数。

    #include "apue.h"
    #include <errno.h>
    #define CL_OPEN "open"         /* client's request for server */
    
    extern char  errmsg[];  /* error message string to return to client */
    extern int   oflag;     /* open() flag: O_xxx ... */
    extern char *pathname;  /* of file to open() for client */
    
    int      cli_args(int, char **);
    void     request(char *, int, int);
    

    服务进程的main函数,版本1

    main函数读取s-pipe上面的客户的请求(从它的标准输入),并且调用函数request。

    #include    "opend.h"
    char     errmsg[MAXLINE];
    int      oflag;
    char    *pathname;
    int main(void)
    {
        int     nread;
        char    buf[MAXLINE];
    
        for ( ; ; ) {   /* read arg buffer from client, process request */
            if ((nread = read(STDIN_FILENO, buf, MAXLINE)) < 0)
                err_sys("read error on stream pipe");
            else if (nread == 0)
                break;      /* client has closed the stream pipe */
            request(buf, nread, STDOUT_FILENO);
        }
        exit(0);
    }
    

    request函数,版本1

    函数request进行所有的处理工作。它调用函数buf_args来将客户的请求变成标准的参数列表形式,然后调用cli_args处理客户进程的参数。如果所有的工作做好了,那么open会被调用来打开文件,然后send_fd通过s-pipe发送文件描述符号给客户进程( 它的标准输出)。如果遇到了一个错误,那么通过使用我们之前描述的客户服务协议,send_err会被调用来将一个错误消息发送回去。

    #include    "opend.h"
    #include    <fcntl.h>
    void request(char *buf, int nread, int fd)
    {
        int     newfd;
    
        if (buf[nread-1] != 0) {
            sprintf(errmsg, "request not null terminated: %*.*s\n",
              nread, nread, buf);
            send_err(fd, -1, errmsg);
            return;
        }
        if (buf_args(buf, cli_args) < 0) {  /* parse args & set options */
            send_err(fd, -1, errmsg);
            return;
        }
        if ((newfd = open(pathname, oflag)) < 0) {
            sprintf(errmsg, "can't open %s: %s\n", pathname,
              strerror(errno));
            send_err(fd, -1, errmsg);
            return;
        }
        if (send_fd(fd, newfd) < 0)     /* send the descriptor */
            err_sys("send_fd error");
        close(newfd);       /* we're done with descriptor */
    }
    

    buf_args函数

    客户请求是一个以null结束的,空白分割的字符串。下面的函数buf_args会将这个字符串变成标准argv形式的参数列表,然后调用用户函数处理相应的参数。本章后面我们将要使用buf_args函数。我们使用ISO的标准C函数strtok来将字符串分割成各个参数。

    #include "apue.h"
    #define MAXARGC     50  /* max number of arguments in buf */
    #define WHITE   " \t\n" /* white space for tokenizing arguments */
    /*
     * buf[] contains white-space-separated arguments.  We convert it to an
     * argv-style array of pointers, and call the user's function (optfunc)
     * to process the array.  We return -1 if there's a problem parsing buf,
     * else we return whatever optfunc() returns.  Note that user's buf[]
     * array is modified (nulls placed after each token).
     */
    int buf_args(char *buf, int (*optfunc)(int, char **))
    {
        char    *ptr, *argv[MAXARGC];
        int     argc;
    
        if (strtok(buf, WHITE) == NULL)    /* an argv[0] is required */
            return(-1);
        argv[argc = 0] = buf;
        while ((ptr = strtok(NULL, WHITE)) != NULL) {
            if (++argc >= MAXARGC-1)    /* -1 for room for NULL at end */
                return(-1);
            argv[argc] = ptr;
        }
        argv[++argc] = NULL;
    
        /*
         * Since argv[] pointers point into the user's buf[],
         * user's function can just copy the pointers, even
         * though argv[] array will disappear on return.
         */
        return((*optfunc)(argc, argv));
    }
    

    cli_args函数

    被buf_args调用的服务进程的函数是cli_args。它会检查客户进程发送了正确的促使数目,然后将其中的路径和打开模式存放在全局的变量中去。函数代码如下:

    #include    "opend.h"
    /*
     *This function is called by buf_args(), which is called by
     *request().  buf_args() has broken up the client's buffer
     *into an argv[]-style array, which we now process.
     */
    int cli_args(int argc, char **argv)
    {
        if (argc != 3 || strcmp(argv[0], CL_OPEN) != 0) {
            strcpy(errmsg, "usage: <pathname> <oflag>\n");
            return(-1);
        }
        pathname = argv[1];     /* save ptr to pathname to open */
        oflag = atoi(argv[2]);
        return(0);
    }
    

    这样就完成了打开文件服务进程,这个进程使用客户进程的fork和exec运行。fork之前会创建一个单个的s-pipe,然后使用这个s-pipe来在客户进程和服务进程之间进行通信。通过这个架构,对与每个客户,我们都有一个服务。

    译者注

    原文参考

    参考: APUE2/ch17lev1sec5.html

    相关文章

      网友评论

        本文标题:APUE读书笔记-17高级进程通信(14)

        本文链接:https://www.haomeiwen.com/subject/obhwrktx.html