株洲做网站公司,广西住房和城乡建设厅网站主页,凡科互动网站,淘宝网站如何推广#x1f308;个人主页#xff1a;Yui_ #x1f308;Linux专栏#xff1a;Linux #x1f308;C语言笔记专栏#xff1a;C语言笔记 #x1f308;数据结构专栏#xff1a;数据结构 #x1f308;C专栏#xff1a;C 文章目录 1.什么是管道 #xff1f;2. 管道的类型2.1 匿…个人主页Yui_ Linux专栏Linux C语言笔记专栏C语言笔记 数据结构专栏数据结构 C专栏C 文章目录 1.什么是管道 2. 管道的类型2.1 匿名管道2.1.1 介绍pipe()2.1.2 pipe()简单示例父子进程通过管道通信2.1.3 管道的4种情况与5种特性2.1.4 匿名管道原理2.1.5 用fork来共享管道的原理2.1.6 站在文件描述符角度-深度理解管道2.1.7 站在内核角度-管道的本质 3. 匿名管道总结 1.什么是管道
管道Pipe是一种常见的进程间通信IPCInter-Process Communication机制在 Unix/Linux 系统中尤其重要。它允许一个进程的输出直接作为另一个进程的输入而不需要使用中间文件。管道通常用于将多个命令连接起来让它们像流水线一样处理数据。 管道在 Unix/Linux 系统中提供了一种简便的机制允许数据在不同进程之间传递。它提供了一个缓冲区数据写入管道的一端写端然后可以从另一端读端读取。管道的本质是一种半双工的通信机制即数据只能沿一个方向流动。 提问有没有一些直观的管道的利用 当然。其实早在Linux的指令学习中我们就已经接触到了管道。就是这个符号|。
ubuntuVM-20-9-ubuntu:~/pipeTest$ ls -l
total 24
-rwxrwxr-x 1 ubuntu ubuntu 16576 Nov 5 11:41 a.out
-rw-rw-r-- 1 ubuntu ubuntu 1285 Nov 5 11:40 pipeTest1.c
ubuntuVM-20-9-ubuntu:~/pipeTest$ ls -l|grep pipeTest1.c
-rw-rw-r-- 1 ubuntu ubuntu 1285 Nov 5 11:40 pipeTest1.c
ubuntuVM-20-9-ubuntu:~/pipeTest$ 这就是一个管道的简单使用我们都知道在大部分Linux的指令都是一个可执行文件运行起来就是一个进程。ls -l的作用就是显示当前目录文件的信息现在我们通过|将这个显示的信息通过管道传递给grep不就实现了两个进程间的相互通信了嘛。这就是管道的核心作用实现进程间的通信高效传递数据避免了使用临时文件的麻烦.
2. 管道的类型
管道存在两种类型
匿名管道用于父子进程或者兄弟进程间的数据传递没有名字仅限具有亲缘关系的进程。命名进程具有文件名可以在不相干的进程间使用。
2.1 匿名管道
匿名管道通过pipe()创建。
2.1.1 介绍pipe()
#include unistd.h
int pipe(int pipefd[2]);pipefd是一个数组它包含两个元素分别是管道的读端和写端的文件描述符。
pipefd[0]读端用于读取数据。pipefd[1]写端用于写入数据。 pipe()创建一个管道并将两个文件描述符存储在pipefd数组中。管道的数据流是单向的数据从写端流向读端。 关于返回值成功返回0.失败返回-1. 使用pepe()的基本流程
创建管道调用pipe()函数。使用fork()创建一个子进程。在父进程关闭写端使用读端读取数据。在子进程中关闭读端使用写端将数据传输给父进程。
2.1.2 pipe()简单示例父子进程通过管道通信
//本代码用来测试子进程提供匿名管道将信息传递给父进程 24/11/5
#include stdio.h
#include unistd.h
#include sys/wait.h
#include sys/types.h
#include stdlib.h
#include string.h
#include stdbool.h
#define SIZE 1024void writer(int wfd)
{char buf[SIZE];const char* str hello father,i am child;int count 1;pid_t id getpid();while(true){//格式化输入snprintf(buf,sizeof(buf)-1,message:%s,pid:%d,times:%d,str,id,count);write(wfd,buf,strlen(buf));count1;sleep(1);}
}void reader(int rfd)
{char buf[SIZE];while(true){ssize_t n read(rfd,buf,sizeof(buf)-1);if(n -1){perror(read);return;}printf(%s\n,buf);}}int main()
{//文件标识符int fd[2];if(pipe(fd) 0){//errorperror(pipe error);return 1;}pid_t id fork();if(id0){perror(fork error);return 1;}else if(id 0){//child//关闭读端close(fd[0]);writer(fd[1]);exit(1);}//fatherclose(fd[1]);reader(fd[0]);wait(NULL);return 0;
}运行结果
如此我们我们便实现了父子间的管道通信。 pipe() 是一个非常重要的系统调用它为进程间通信提供了一个简单而高效的机制。通过管道多个进程可以协作完成任务并且避免了中间文件的使用。在父子进程之间的通信或在处理大量数据时管道通常是最常用的 IPC 方式之一。
2.1.3 管道的4种情况与5种特性
4种情况
管道内部没有数据时且子进程不关闭自己的写端文件fd读端父就会堵塞等待直到pipe有数据管道内部被写满且父进程读端不关闭自己的fd写端写满后就会堵塞等待。对于写端而言不写了且关闭了pipe读端会将pipe中的数据读完最后就会读到返回值为0表示读结束类似读到了文件的结尾。读端不读且关闭写再写OS会直接终结写入的进程子进程通过信号13SIGPIPE来杀死进程。 5种特性自带同步机制。血缘关系进行通信常见于父子进程。pipe是面向字节流的。父子进程退出管道自动释放文件的生命周期是跟随进程的。管道只能单向通信半双工的一种特殊情况。
2.1.4 匿名管道原理 通过父子进程继承关系再将文件描述符关闭实现一端写一端读就是匿名管道. 创建匿名管道的步骤 父进程以读写的方式打开文件。父进程fork创建子进程子进程会拷贝一份PCB结构PCB中会包含files_struct结构files_struct中有一个指向struct file文件的指针数组而文件描述符就是这个数组的下标。拷贝完成后子进程也就存在了指向struct file的对应文件描述符。又因为struct file是独属于的文件的和进程没有关系也就不用拷贝也就是说此时父子进程同时指向了一块公共区域struct file不同进程看见同一份资源。write是系统调用接口会将数据放在内核缓冲区底层会定期刷新缓冲区将内容写入磁盘。匿名管道是一个半双工的通信机制也就是说数据只能沿一个方向流动为了实现半双工的通信方式父子进程需要关闭各种不需要的文件描述符。 2.1.5 用fork来共享管道的原理
使用fork后
2.1.6 站在文件描述符角度-深度理解管道
0 1 2 分别为 标准输入标准输出标准错误。
2.1.7 站在内核角度-管道的本质
Linux下一切皆文件. 所以我们也应该用看待文件的眼观去理解管道。 我们可以将管道Pipe理解为一种特殊类型的文件。实际上管道确实是由操作系统内部的内存缓冲区实现的它通过文件描述符来进行访问就像其他普通文件一样。通过这种类比我们可以从文件的角度理解管道。
3. 匿名管道总结
通过匿名管道进程可以轻松地进行数据交换而不需要借助临时文件或其他外部资源。尽管管道有一些局限性如单向传输和缓冲区限制它仍然是许多进程间通信场景中常见的选择。 注意管道是半双工的数据只能向一个方向流动需要双方通信时可以建立两个管道。