Linux C:管道的实现原理,命名管道
目录
一、管道
二、利用管道将写进程和都进程连接起来
三、命名管道
一、管道
在Unix/Linux 中 命令行
cmd1 | cmd2 #例如 history | grep sqlplus
其中 cmd1 是 cmd2 是Linux中独立的程序 , 而 “ | ” 符号在Linux 称之为管道符。管道一端用来读另一端用来写。 把前一个进程的输出结果作为后一个进程的输入参数。例如
history | grep sqlplus 命令,前面一个是展示所有的历史命令 ,而后面一个是对输入中过滤出待关键字的sqlplus 的字符串。 两个合起来就是 展示所有的带”sqlplus“的历史命令。
在C程序中,方法 int flag = pipe(int pd[2]); 方法,输入参数是一个至少2个元素的int数组。用来创建两个文件描述符,这两个文件描述符链接同一个临时文件, pd[0]用于从管道中读数据, pd [1]用于从管道中写数据。 如果创建成功flag 值为0 否则为-1。.

注意:在创建pipe 后,其中的一个文件描述符 pd[0] 没有'w'权限,只有’r‘权限,而 pd[1] 没有'r'权限,只有’w‘权限。
对文件描述符和IO重定向不了解的可以看看:
https://blog.csdn.net/superSmart_Dong/article/details/118531682
在下例代码展示了用子进程和父进程利用管道读写数据的过程。由于子进程创建时会完全继承父进程的文件描述符。意味着父进程中存在pd[2],那么子进程也有一样的pd[2]。所以一个进程如果当作管道的写进程,那么它的读文件描述符就要先关闭,如果一个进程如果当作管道的读进程,那么它的写文件描述符就要关闭。
#include
#include
#include
#include
int pd[2] ,n,i;
char line[256];int main(){pipe(pd); //pd[1]用于写 , pd[0]用于读printf("pd[ %d , %d ]",pd[0],pd[1]);if(fork()){//parent分支printf("parent %d close pd[0] \n",getpid());close(pd[0]);i =0;while( i++ <10){//假设父进程向管道写入10次;n = write(pd[1],"I AM YOUR PAPA",16);printf("parent %d write %d byte to pipe\n",getpid(),n);}printf("parent %d exit\n",getpid());}else{//child 分支printf("child %d close pd[1] \n",getpid());close(pd[1]);while( 1){//管道读入诺干;n = read(pd[0],line,128);if(n){printf(" child %d read %d byte from pipe\n :%s \n",getpid(),n,line);}else{exit(0);}}}}
输出结果可能不为一:其中一种输出结果如图。

二、利用管道将写进程和都进程连接起来
在Linux 中当 sh 获取命令行 cmd1 | cmd2 时,会复刻出一个子进程sh。子进程sh会观察命令行中是否有 ”|“ 管道符号,把命令行划分为头部和尾部
然后子进程执行一下代码段:从而实现两个进程通过管道和重定向IO实现对子进程的标准输入的内容时父进程的标准输出的内容。
int pd[2];
pipe(pd);
int pid =fork();
if(pid){close(pd[0]); //父进程用于从管道中写入数据,所以关闭读fd(pd[0])close(1); dup(pd[1]); //拿pd[1]复制出一个最小未使用的fd = 1,让标准输出指向管道pd[1]所指的物理文件close(pd[1]); //关闭原来的pd[1]exec(cmd1);
}else{close(pd[1]); //子进程用于从管道中读入数据,所以关闭写fd(pd[1])close(0); dup(pd[0]); //拿pd[0]复制出一个最小未使用的fd =0,让标准输入指向管道pd[0]所指的物理文件close(pd[0]); //关闭原来的pd[0]exec(cmd2);
}
三、命名管道
命名管道又叫做FIFO,在C语言中可以为管道命名。一个被赋予名字的管道。可以实现在两个独立进程或者两个项目工程中进行数据交互。命名管道在文件系统中以特殊文件的形式存在,不是临时文件,意味着,如果没有把命名管道文件进行 rm 或者 unlink 删除,则该管道会一致存在下去,除非储存介质损坏。
在 sh 中:创建命名管道的命令为:
mknod pipename p
在C程序中,创建命名管道的系统调用为
int r =mknod("pipename",S_IFIFO,0)
可以利用在命名管道实现两个独立进程的数据交互
/*********写管道进程*****************/#include
#include
#include
#include
char *line = "name pipe message";
int main(){int fd ;mknod("mypipe",I_SFIFO,0);fd = open("mypipe",O_WRONLY);write(fd,line,strlen(line));close(fd);
}
在写另外一个用于读管道的C程序
/*********读管道进程*****************/#include
#include
#include int main(){char buf[128];int fd = open("mypipe",O_RDONLY);read(fd,buf,128);printf("%s\n",buf);close(fd);
}
对这两个C程序分别进行编译。如果管道没数据就读内容的话,得到的输入也是空的。就算进程生命结束,创建出来的命名管道依旧是存在的。
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
