• Linux基础教程:10、进程通讯(管道通讯)


    进程之间是独立的,但是又是有联系的,他们可以使用管道、信号、socket、消息队列和共享内存来实现通信,那么我们先来看看进程之间如何使用管道:

    1. #include<stdio.h>
    2. #include<stdlib.h>
    3. #include<unistd.h>
    4. #include<string.h>
    5. #include<sys/types.h>
    6. #include<sys/wait.h>
    7. int main()
    8. {
    9.       pid_t pid;
    10.       int fd[2];
    11.       int ret=pipe(fd);
    12.       if(ret==-1)
    13.       {
    14.               printf("pipe error!\n");
    15.               exit(1);
    16.       }
    17.       pid=fork();
    18.       if(pid==-1)
    19.       {
    20.               perror("fork error\n");
    21.               exit(1);
    22.       }
    23.       else if(pid>0)
    24.       {
    25.                       waitpid(pid,NULL,WNOHANG);
    26.                       close(fd[1]);
    27.                       char buf[1024]={0};
    28.                       int len=0;
    29.                       len=read(fd[0],buf,sizeof(buf));
    30.                       printf("parent receive meassge:%s\n",buf);
    31.                       close(fd[0]);
    32.                       sleep(2);
    33.       }
    34.       else if(pid==0)
    35.       {
    36.                       close(0);
    37.                       char * str="this is a message by child send!\n";
    38.                       write(fd[1],str,strlen(str)+1);
    39.                       close(fd[1]);
    40.                       sleep(2);
    41.       }
    42.       return 0;
    43. }
    44.                                            

    要注意几个点,管道是需要在进程创建之前在再创建的,如果在进程之后创建管道的话顺序就乱了,管道将不会生效,而且这个半双工过程,也就说我们一次只能通信一次,要么是a向b发信息,要么就是b向a,不能ab同时,所以我这里就拿父子进程来讲解;

    首先我们创建管道(pipe函数):

    1. int fd[2];
    2. int ret=pipe(fd);

    他需要一个int数组,两个元素,一个是读端(fd[0])一个是写端(fd[1]),pipe这个函数就是用来创建管道的,他的参数就是这个数组;

    1. close(fd[1]);
    2. char buf[1024]={0};
    3. int len=0;
    4. len=read(fd[0],buf,sizeof(buf));
    5. printf("parent receive meassge:%s\n",buf);
    6. close(fd[0]);
    7. sleep(2);

    在我们要写或者读一个内容的时候,如果是写我们就应该把读的管道描述符关闭,也就是这里的fd[0],同理如果是读的话就是关闭写了;

    使用读写流也是read和write之前我讲过的,参数的话第一个就是描述符,第二个就是数据,第三个就是长度,这里注意read的返回值是读取到的真实长度,如果读取失败的话就是返回-1;如果想要父子之间一直保持通讯的话我们就不能关闭读写流了:

    1. #include<stdio.h>
    2. #include<stdlib.h>
    3. #include<unistd.h>
    4. #include<string.h>
    5. #include<sys/types.h>
    6. #include<sys/wait.h>
    7. int main()
    8. {
    9.       pid_t pid;
    10. int fd[2];
    11. int ret=pipe(fd);
    12. if(ret==-1)
    13. {
    14. printf("pipe error!\n");
    15. exit(1);
    16. }
    17. pid=fork();
    18.       if(pid==-1)
    19.       {
    20.               perror("fork error\n");
    21.               exit(1);
    22.       }
    23.       else if(pid>0)
    24.       {
    25. char buf[1024]={0};
    26. while(1)
    27. {
    28. waitpid(pid,NULL,WNOHANG);
    29. int len=0;
    30. len=read(fd[0],buf,sizeof(buf));
    31. printf("parent receive meassge:%s\n",buf);
    32. sleep(2);
    33. char * str = "fighing ,child ,you are my hope!\n";
    34. write(fd[1],str,strlen(str)+1);
    35. sleep(2);
    36. }
    37.       }
    38.       else if(pid==0)
    39.        
    40. {
    41. char buf[1024]={0};
    42. while(1)
    43. {
    44. char * str="fighting , parent , you are my example!\n";
    45. write(fd[1],str,strlen(str)+1);
    46. sleep(2);
    47. int len=0;
    48. len = read(fd[0],buf,sizeof(buf));
    49. sleep(2);
    50. printf("child receive message:%s\n",buf);
    51. }
    52.                
    53.       }
    54.       return 0;
    55. }

    父子进程之间通讯要注意:

    1、要先创建管道,再创建进程;2、父子进程要互相读写数据的时候就不需要关闭读写端,卡好时间即可;

    匿名管道的含义:

    匿名管道就是类似于 ls | wc –l这种由| 连接的一个或者多个命令,|的前一个命令的输出会作为后一个命令的输入;

    父子之间通讯是共用一个管道,管道的两端只能进行读写操作中的一种,因此父子通讯时应该关闭父子进程中的一个文件描述符,比如在父进程中写操作,在子进程中读操作时,我们就应该使用close函数关闭父进程中的读端和子进程的写端;这样就可以通过向管道中读写数据来实现进程之间的通讯;

    总结一下,结合之前的父子通讯内容,我们多加了循环和管道,循环的目的是为了可以更容易的看到结果,管道就是用来父子通讯的,父子通讯时只能一个写一个读,而且要将时间拿捏得死死的才能通讯成功,如果只是通讯一次的话我们就需要在一个进程进行读/写操时关闭另一个的写/读端;

  • 相关阅读:
    自己动手实现一个深度学习算法——七、卷积神经网络
    Service Mesh 解决问题
    Element---基于VUE的桌面端组件库
    C++杂讲 类 初讲
    负载均衡的常见实现方式
    牛客-TOP101-BM66
    基于KDtree的电路故障检测算法的MATLAB仿真
    【React 源码】(五)React 应用的启动过程
    Dapr在Java中的实践 之 状态管理
    ElasticSearch学习
  • 原文地址:https://blog.csdn.net/aiwanchengxu/article/details/127940594