进程间通信( 管道 )

本文介绍了进程间通信中的管道机制,包括匿名管道和命名管道的特性、使用方法以及示例代码。匿名管道适用于有亲缘关系的进程,而命名管道可在同一主机的任意进程间通信。管道本质上是内核中的缓冲区,具有单向、半双工的特点,并涉及读写阻塞、端口关闭等行为。通过管道,进程可以实现数据的传递和命令的链接,如在shell中使用管道符`|`连接`ps`和`grep`命令。
摘要由CSDN通过智能技术生成

进程间通信( 管道 )


前言

  进程间通信: 进程间的几种通信方式的学习(管道, 共享内存, 消息队列, 信号量)
   为什么进程间无法直接进行通信?
    因为进程之间具有独立性, 每个进程访问的都是自己的独立的虚拟地址空间, 使用的都是虚拟地址, 通过页表映射到物理内存. 因此就算将数据的内存地址交给其他进程, 其他进程也无法访问(当然其实也无法直接给), 只能通过操作系统提供的几种方式来进行.
本质上来说是操作系统为多个进程提供了一处公共的数据传输媒介(内存)。

一、管道

管道用于传输数据
特性半双工通信–可以选择方向的单向通信
本质管道就是内核中的一块缓冲区(内存)
分类匿名管道,命名管道
  匿名管道:管道没有名字--缓冲区没有标识符;
   只能用于具有亲缘关系的进程间通信
 命名管道:管道具有标识符;
   可用于同一主机上的任意进程间通信
 匿名管道:
int pipe(int pipefd[2])

在这里插入图片描述

在这里插入图片描述


 pipefd[0]--读
 pipefd[1]--写
 返回值:成功返回0;失败返回-1;
  匿名管道一定要在创建子进程之前创建

代码如下(示例):

  1 #include <stdio.h>
  2 #include <unistd.h>
  3 #include <stdlib.h>
  4 #include <string.h>
  5 int main()
  6 {
  7     int pipefd[2];
  8     int ret = pipe(pipefd);
  9     if(ret < 0){
 10         perror("pipe error");
 11         return -1;
 12     }
 13     pid_t pid = fork();
 14     if(pid < 0){
 15         perror("fork error");
 16         exit(-1);
 17     }else if(pid == 0){
 18         //child
 19         char buf[1024] = {0};
 20         int ret = read(pipefd[0], buf, 1023);
 21         if(ret < 0){
 22             perror("read error");
 23             return -1;
 24         }
 25         printf("buf:%s\n", buf);
 26     }else{
 27         //parent
 28         char *ptr = "今天好困呐!!\n";
 29         int ret = write(pipefd[1], ptr, strlen(ptr));
 30         if(ret < 0){
 31             perror("write error");
 32             return -1;
 33         }
 34         printf("写入成功\n");
 35     }
 36     return 0;
 37 }


结果:
在这里插入图片描述

 通常情况下, 父子进程运行的顺序是不一定的, 一般情况下, 父进程先于子进程运行. 但在这里, 子进程明显先于父进程运行, 这是由于管道的特性所决定的.
管道中的读取特性 :
  1.若管道中没有数据则read会阻塞,管道中数据满了,则write会阻塞。
  2.若管道的所有读端被关闭,则write会触发异常--导致进程退出;
  3.若管道的所有写端被关闭,则read读完所有数据后返回0;




 1.若管道中没有数据则read会阻塞,管道中数据满了,则write会阻塞。

在这里插入图片描述



 2.若管道的所有读端被关闭,则write会触发异常–导致进程退出;
在这里插入图片描述




 3.若管道的所有写端被关闭,则read读完所有数据后返回0;
在这里插入图片描述




 shell中的管道符: | --连接两个命令,将前边命令的结果交给后边命令进行处理
ps -ef | grep pipe模拟实现
ps -ef:将系统中的进程信息写入标准输出
grep pipe:不断从标准输入读取数据,进行匹配过滤.
使用管道连接两个命令之后,将ps进程原本要写入标准输出的数据,不再 写入标准输出,而是通过管道写入端写入管道。grep进程原本从标准输入读取数据,修改为从管道读取端读取数据,进行匹配过滤
1.当前进程作为shell进程,所有命令都是子进程完成的;
2.创建匿名管道;
3.创建一个子进程,先进行标准输出重定向到管道写入端,然后经过程序替换运行ps -ef指令;
4.创建一个子进程,先进行标准输入重定向到管道读取端,然后经过程序替换运行grep pipe指令;
5.子进程等待两个父进程退出;

注意:在进程中把不使用的管道一端一定要关掉,防止一些不必要的问题

  1 #include <stdio.h>
  2 #include <unistd.h>
  3 #include <stdlib.h>
  4 #include <sys/wait.h>
  5 int main()
  6 {
  7     int pipefd[2];
  8     int ret = pipe(pipefd);
  9     if(ret < 0){
 10         perror("pipe error");
 11         return -1;
 12     }
 13     if(fork() == 0){
 14         dup2(pipefd[1], 1);
 15         execlp("ps", "ps", "-ef", NULL);
 16         exit(-1);
 17     }
 18     if(fork() == 0){
 19         dup2(pipefd[0], 0);
 20         execlp("grep","grep", "pipe", NULL);
 21         exit(-1);
 22     }
 23     wait(NULL);
 24     wait(NULL);
 25     return 0;
 26 }

在这里插入图片描述


 命名管道:内核中的缓冲区具有标识符,能够被其他进程找到,因此可用于同一主机上的任意进程间通信
命名管道具有标识符,这个标识符是可见于文件系统的管道文件,但是要注意,这个文件只是一个标识符,只是为了让多个进程 可以通过打开同一个管道文件进而访问内核中的同一块缓冲区进行通信而已。

代码操作:

int mkfifo(const char*pathname,mode_t mode);

在这里插入图片描述

  1 #include <stdio.h>
  2 #include <unistd.h>
  3 #include <stdlib.h>
  4 #include <sys/stat.h>
  5 #include <errno.h>
  6 #include <fcntl.h>
  7 int main()
  8 {
  9     umask(0);
 10     char *fifo_name = "./test.fifo";
 11     int ret = mkfifo(fifo_name, 0664);
 12     if(ret < 0 && errno != EEXIST){
 13         perror("mkfifo error");
 14         return -1;
 15     }
 16     //open(文件名, 打开方式, 权限)
 17     int fd = open(fifo_name, O_RDONLY);
 18     if(fd < 0){
 19         perror("open error");
 20         return -1;
 21     }
 22     printf("open fifo success\n");
 23     return 0;
 24 }

程序阻塞
在这里插入图片描述


 命名管道的打开特性:

  如果命名管道以只读的方式打开,会阻塞直到这个管道被以写的方式打开;
  如果命名管道以只写的方式打开,会阻塞直到这个管道被以读的方式打开;

在这里插入图片描述
写端 :

  1 #include <stdio.h>
  2 #include <unistd.h>
  3 #include <stdlib.h>
  4 #include <errno.h>
  5 #include <fcntl.h>
  6 #include <sys/stat.h>
  7 #include <string.h>
  8 int main()
  9 {
 10     umask(0);
 11     char *fifo_name = "./test.fifo";
 12     int ret = mkfifo(fifo_name, 0664);
 13     if(ret < 0 && errno != EEXIST){
 14         perror("mkfifo error");
 15         return -1;
 16     }
 17     int fd = open(fifo_name, O_WRONLY);
 18     if(fd < 0){
 19         perror("open error");
 20         return -1;
 21     }
 22     while(1){
 23         char buf[1024] = {0};
 24         scanf("%s", buf);
 25         int ret = write(fd, buf, strlen(buf));
 26         if(ret < 0){
 27             perror("write error");
 28             return -1;
 29         }
 30     }
 31     close(fd);
 32     return 0;
 33 }

在这里插入图片描述

MFC是微软基于C++的一个应用程序框架,它可以帮助开发人员快速创建Windows应用程序。进程间通信(IPC)是不同进程之间进行数据交换和通信的一种方法。管道是一种常见的IPC机制,它允许两个进程之间进行双向通信。 在MFC中,使用管道进行进程间通信可以分为两个步骤:创建管道和使用管道进行通信。 首先,需要创建一个管道。可以使用CreatePipe函数来创建匿名管道,它接受两个参数,第一个参数是用于接收管道句柄的指针,第二个参数是用于发送管道句柄的指针。成功创建管道后,你将获得两个句柄,一个用于读取数据,一个用于写入数据。 然后,可以使用ReadFile和WriteFile函数来读取和写入管道中的数据。这些函数可以传入一个管道句柄,一个缓冲区来存储数据以及数据的长度。通过这些函数,可以在两个进程之间传递数据。 如果需要实现双向通信,可以在每个进程中使用一个管道来进行读取和写入操作。这样,两个进程就可以通过各自的管道进行双向通信了。例如,进程A使用管道A向进程B发送数据,进程B使用管道B向进程A发送数据。 总结起来,MFC可以使用管道进行进程间通信,通过创建管道和使用ReadFile和WriteFile函数来实现数据的读取和写入。如果需要双向通信,则可以在两个进程中分别创建管道来进行双向数据传输。
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李憨憨_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值