linux之进程间通信——管道

Posted 努力学习的少年

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了linux之进程间通信——管道相关的知识,希望对你有一定的参考价值。

目录

进程间是怎么通信的

管道

匿名管道

匿名管道是如何实现进程间通信

内核角度理解匿名管道

管道的读写规则

 情景1

情景2

 情景3

​ 情景4

命名管道

创建命名管道

命令行方式创建

函数创建

命名管道的应用场景 

场景1

 场景2

场景3


进程间是怎么通信的

之前我们说过,进程与进程之间是相互独立的,它们的数据也是绝对独立的,那么如果一个进程要向另一个进程发送数据,就需要借助第三方资源,这个第三方资源必须让这两个进程都能看到,且通信的时候,互不影响对方,在内核中,有几种方式能够实现进程通信,今天要讲的是管道

管道

所谓的管道,是内存中的一个缓存文件,进程A在管道写入数据,实际是写入到内核中的缓存文件中,进程B从管道中读取数据,实际是从内核的缓存文件中读取数据。

 管道的传输数据是单向的,只能由一个进程写入,一个进程读出

匿名管道

概念
匿名管道是没有名字的,它是特殊文件,它只创建在内存中,不存在我们磁盘中,即用完就销毁了。

#include<unistd.h>

int pipe(int fd[2]);

功能:在内核中创建一个匿名管道

参数:

fd:文件描述符数组,其中将f[0]存储读端的文件描述符,fd[1]存储写端的文件描述符。

返回值:成功返回0,失败返回-1.

 匿名管道一般适用于有血缘关系之间的通信,例如父子进程,兄弟进程 等       

匿名管道是如何实现进程间通信

1.父进程利用pipe创建出一个匿名管道,得到的文件表示符指向管道的读端和写端

2.利用fork生成一个子进程,子进程的文件描述符也指向管道的读端和写端。

3.关闭父进程的读端和关闭子进程的写端 或者 关闭父进程的写端和关闭子进程的读端。

这样匿名管道就创建完成。

ps aux | grep myfile 

我们知道“ | ”这也是一个管道,它其实也是一个匿名管道,上面这条命令是将ps 进程输出的数据输送到管道中,然后将grep从管道中读取数据,并查找myfile文件,然后将结果打印到屏幕上

 

 

 

 内核角度理解匿名管道

当父进程创建子进程的时候,系统会给子进程创建file_struct和file的数据结构,然后将父进程的file_struct和file的中数据拷贝给子进程的的file_struct和file,这样父进程和子进程就能够指向同一个管道。

 

代码:

 

管道的读写规则

 情景1

让子进程一直往管道中写入数据,父进程的读端不关闭,但不读取数据。 

 

结果 

刚开始,子进程一直往管道中写入数据,当管道写满之后,则子进程就不会往管道中写入数据,子进程就被阻塞等待,等父进程来读取数据时,子进程才会被运行起来。如图所示:

那么我们既然知道管道是有大小的,我们来测试一下我这个版本的linux管道大小是多少。

此时的父进程还是在睡眠,不读取数据。

输出结果: 

 

当输出到65536的时候,则不在屏幕上打印数据,则说明子进程往管道写入的数据已满,所以我这个版本的linux的匿名管道的大小为65536个字节。

情景2

当子进程往管道中写入一定的数据后,就不再往管道中写入数据,并让父进程一直读取管道中的数据。

子进程 

父进程: 

 当子进程只往管道中写入数据时,而父进程不断的往管道中读取数据,当父进程将管道中的数据读完之后,则父进程就会被阻塞等待,直到子进程往管道中写数据时,父进程才会读取管道中的数据。

 

 情景3

当子进程往管道中写完数据后就关闭写端,父进程一直在读取.

 结果:

子进程往管道中写入三条数据,同时父进程将这三条数据给读取上来,子进程关闭写端后,父进程去读取数据时,read读不到数据,并返回0。

 情景4

当子进程一直往管道中写数据,父进程休息5秒后关闭读端。        

 

结果:

前5秒上显示器打了5条 i am child,直到第5秒,父进程的读端关闭后,子进程就被系统给杀掉了,不在打印i am child。

总结:

1.当管道中没数据的时候,读端的进程就会被阻塞等待(前提写端没有关闭)。

2.当管道中的数据被写满的时候,写端就会被阻塞等待(前提读端没有关闭)。

3.当写端关闭的时候,读端把数据读完之后,则在读取数据时,read会返回0.

4.当读端关闭的时候,写端的进程会自动的被操作系统给杀掉。

5.半双工通信,只能有一端写入,一端读取。

命名管道

匿名管道是通过子进程能够继承父进程的pcb,file和file_struct等结构体,使父子进程(兄弟进程等有血缘关系的进程)能够看到同一个管道,可是两个没有任何的关系进程是没办法这种方式看到同一个管道的。然而系统有命名管道可以让这两个不同的进程看到同一个管道,实现通信。

我们可以在磁盘中创建一个管道文件,当要通信的时候,不同的进程以不同的读或写的方式往磁盘上打开这个管道文件,然后将这个管道文件加载到缓存内核中,然后一个进程往内核中的管道文件中写数据,另一个进程就往内核中的管道文件中读数据,原理是跟匿名管道是类似的。

命名管道是存在磁盘上,它是有文件名的,命名管道让不同的进程在同一路劲下打开命名管道,然后进行通信,它们在内存所写的数据不会刷新到磁盘上。它的存在只是为了让进程能够通过路径找到这个管道文件,然后实现通信

创建命名管道

命令行方式创建

mkfifo pipe

在磁盘上创建一个名字为pipe的命名管道。

命名管道的文件属性是p。

函数创建

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

filename:创建管道的文件名

mode:管道的权限属性

返回值:成功返回0,失败返回-1.

 

命名管道的应用场景 

场景1

利用命名管道实现一个进程对另一个进程的通信 

思路:client进程从键盘读取到的数据传输到命名管道上,然后server进程再去从命名管道中读取数据,然后将信息打印到屏幕上。 

头文件:

makefile文件:

client.c文件:

 server.c文件

 运行结果:

 场景2

一个进程利用命名管道给另一个进程输入某个指令,让该进程执行该指令。

 client.c文件

 server.c文件

运行结果: 

场景3

用命名管道实现文件拷贝

思路:进程A读取myfile文件的内容,然后将这些数据写到管道中,进程B创建出一个新文件myfile_1,然后进程B从管道中读取数据并写入到新文件myfile_1中,直到结束。

client.c文件 

 

 

server.c 文件

 

管道的特点:

1.一般而言,进程退出,管道释放,管道的生命周期是随进程的。

2.一般而言,内核会对管道操作进行同步和互斥。

3.管道是半双工的,只能有一个方向流动,需要双方通信的时候,是会建立起两个管道。

  好啦,今天的内容就分享到这里,喜欢的读者给个三连呗,感谢你的支持。

以上是关于linux之进程间通信——管道的主要内容,如果未能解决你的问题,请参考以下文章

Linux进程通信之匿名管道

linux之进程间通信——管道

Linux之------进程间通信

[ Linux ] 进程间通信之共享内存

Linux进程间通信之管道

linux c之通过管道实现兄弟间进程通信: