zoukankan      html  css  js  c++  java
  • 《APUE》读书笔记第十七章高级进程间通信

      本章主要介绍了基于STREAM的管道和UNIX域套接字,这些IPC可以在进程间传送打开文件描述符。服务进程可以使用它们的打开文件描述符与指定的名字相关联,客户进程可以使用这些名字与服务器进程通信。

    1、基于STREAMS的管道

      STREAMS pipe是一个双向(全双工)管道,单个STREAMS管道就能向父、子进程提供双向的数据流。如下图所示:

    下面采用STREAMS管道实现加法协同进程实例,程序如下:

    View Code
     1  1 #include <stdio.h>
     2  2 #include <stdlib.h>
     3  3 #include <unistd.h>
     4  4 #include <errno.h>
     5  5 #include <string.h>
     6  6 #include <signal.h>
     7  7 
     8  8 #define MAXLINE 1024
     9  9 
    10 10 static void sig_pipe(int signo)
    11 11 {
    12 12     printf("SIGPIPE caught\n");
    13 13     exit(1);
    14 14 }
    15 15 int s_pipe(int fd[2])
    16 16 {
    17 17     return pipe(fd);
    18 18 }
    19 19 int main()
    20 20 {
    21 21     int     n;
    22 22     int     fd[2];
    23 23     pid_t   pid;
    24 24     char    line[MAXLINE];
    25 25 
    26 26     signal(SIGPIPE,sig_pipe);
    27 27     s_pipe(fd);
    28 28     if((pid = fork()) == -1)
    29 29     {
    30 30         perror("fork() error");
    31 31         exit(-1);
    32 32     }
    33 33     if(pid == 0)  //子进程用fd[1]
    34 34     {
    35 35         close(fd[0]);
    36 36         dup2(fd[1],STDIN_FILENO);
    37 37         dup2(fd[1],STDOUT_FILENO);
    38 38         execl(".//add","add",(char *)0);
    39 39         exit(0);
    40 40     }
    41 41     else   //父进程用fd[0]
    42 42     {
    43 43         close(fd[1]);
    44 44         while(fgets(line,MAXLINE,stdin) != NULL)
    45 45         {
    46 46             n = strlen(line);
    47 47             if(write(fd[0],line,n) != n)
    48 48             {
    49 49                 perror("write() error to pipe");
    50 50                 exit(-1);
    51 51             }
    52 52             if((n =read(fd[0],line,MAXLINE)) < 0)
    53 53             {
    54 54                 perror("read() error to pipe");
    55 55                 exit(-1);
    56 56             }
    57 57             if(n==0)
    58 58             {
    59 59                 printf("child close pipe\n");
    60 60                 break;
    61 61             }
    62 62             line[n] = '\0';
    63 63             fputs(line,stdout);
    64 64         }
    65 65         exit(0);
    66 66     }
    67 67 }

     在APUE2 P469中这样讲:“solaris支持STREAMS管道,Linux的可选附加包也提供了STREAMS管道。”这个包没有安装上,程序不能正常运行。

    1.2命名的STREAMS管道

      管道仅在相关进程之间使用,例如子进程集成父进程的管道。无关进程可以使用FIFO进行通信,但是这仅仅提供单向通信。STREAMS机制提供了一种有效的途径,使得进程可以给予管道一个文件系统的名字,避免了单向FIFO的问题。操作函数原型如下:

    #include <stropts.h>
    int fattach(int fildes, const char *path);  //给STREAMS管道一个系统文件中的名字
    int fdetach(const char *path); //撤销STREAMS管道文件与文件系统中名字的关联

    2、UNIX域套接字

      UNIX域套接字用于在同一台机器上运行的进程之间的通信,UNIX域套接字仅仅复制数据,不执行协议处理,不需要添加或删除网络报头,无需计算校验和,不要产生顺序号,无需发送确认报文。UNIX域套接字是套接字和管道之间的结合物,提供流和数据报两种接口。

    UINX域套接字的好处:

    (1)在同一台主机上进行通信时,是不同主机间通信的两倍

    (2)UINX域套接口可以在同一台主机上,不同进程之间传递套接字描述符

    (3)UINX域套接字可以向服务器提供客户的凭证(用户id或者用户组id)

    UINX域套接字使用的地址通常是文件系统中一个文件路径,这些文件不是不同的文件,只能作为域套接字通信,不能读写。创建函数如下:

    #include <sys/socket.h>
    int socketpair(int domain, int type, int protocolint " sv [2]);

    利用UNIX域实现全双工管道,程序如下:

    View Code
     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <unistd.h>
     4 #include <errno.h>
     5 #include <string.h>
     6 #include <signal.h>
     7 #include <sys/socket.h>
     8 #define MAXLINE 1024
     9 
    10 static void sig_pipe(int signo)
    11 {
    12     printf("SIGPIPE caught\n");
    13     exit(1);
    14 }
    15 int s_pipe(int fd[2])
    16 {
    17     return socketpair(AF_UNIX,SOCK_STREAM,0,fd);  //创建UNIX域套接字
    18 }
    19 int main()
    20 {
    21     int     n;
    22     int     fd[2];
    23     pid_t   pid;
    24     char    line[MAXLINE];
    25 
    26     signal(SIGPIPE,sig_pipe);
    27     s_pipe(fd);
    28     if((pid = fork()) == -1)
    29     {
    30         perror("fork() error");
    31         exit(-1);
    32     }
    33     if(pid == 0)
    34     {
    35         close(fd[0]);
    36         dup2(fd[1],STDIN_FILENO);
    37         dup2(fd[1],STDOUT_FILENO);
    38         execl(".//add","add",(char *)0);
    39         exit(0);
    40     }
    41     else
    42     {
    43         close(fd[1]);
    44         while(fgets(line,MAXLINE,stdin) != NULL)
    45         {
    46             n = strlen(line);
    47             if(write(fd[0],line,n) != n)
    48             {
    49                 perror("write() error to pipe");
    50                 exit(-1);
    51             }
    52             if((n =read(fd[0],line,MAXLINE)) < 0)
    53             {
    54                 perror("read() error to pipe");
    55                 exit(-1);
    56             }
    57             if(n==0)
    58             {
    59                 printf("child close pipe\n");
    60                 break;
    61             }
    62             line[n] = '\0';
    63             fputs(line,stdout);
    64         }
    65         exit(0);
    66     }
    67 }

    add是单独的程序,共程序调用,执行结果如下:

    2.1命令UNIX域套接字

      UNIX域套接字的地址有sockaddr_run结构表示。

      #define UNIX_PATH_MAX 108
      struct sockaddr_un {
        sa_family_t sun_family; /* AF_UNIX */
        char sun_path[UNIX_PATH_MAX]; /* pathname };

    写个程序,将一个地址绑定一UNIX域套接字,程序如下:

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <errno.h>
    #include <sys/socket.h>
    #include <sys/un.h>
    #include <stddef.h>
    int main()
    {
        int fd,size;
        struct sockaddr_un  un;
        un.sun_family = AF_UNIX;
        strcpy(un.sun_path,"foo.socket");
        fd = socket(AF_UNIX,SOCK_STREAM,0);
        size = offsetof(struct sockaddr_un,sun_path) + strlen(un.sun_path);
        if(bind(fd,(struct sockaddr*)&un,size)<0)
        {
            perror("bind() error");
            exit(-1);
        }
        printf("UNIX domain socket bound\n");
        exit(0);
    }

    程序执行结果如下:

    从结果可以看出,如果绑定地址时候,文件已经存在,那么bind请求将会失败,关闭套接字时,并不删除该文件。因此必须保证在应用程序终止前,对该文件进行解除链接操作。

    2.2唯一连接

      服务器进程可以使用标准bind、listen和accept函数为客户进程安排一个唯一的UNIX域连接,客户进程使用connect与服务器进程联系,服务器进程接受了connect请求后,在服务器进程和客户进程之间就存在了唯一的连接。程序参考http://blog.csdn.net/youkuxiaobin/article/details/6965527 http://bbs.chinaunix.net/thread-2183106-1-1.html

  • 相关阅读:
    ThinkPHP 3 的输出
    zookeeper 伪集群模式
    zookeeper
    MVC模式和URL访问
    全民上云时代,如何降低成本?
    华为云教你7天玩转电商应用性能调优,课程免费速来报名!
    一统江湖的大前端(6)commander.js + inquirer.js——懒,才是第一生产力
    一统江湖的大前端(5)editorconfig + eslint——你的代码里藏着你的优雅
    一统江湖的大前端(4)shell.js——穿上马甲我照样认识你
    【Python3网络爬虫开发实战】1.3.1-lxml的安装
  • 原文地址:https://www.cnblogs.com/Anker/p/2830791.html
Copyright © 2011-2022 走看看