Linux进程间通信管道
Posted ╯ Instinct
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux进程间通信管道相关的知识,希望对你有一定的参考价值。
管道
-
管道可以用来在两个进程之间传递数据,如: ps -ef | grep “bash”, 其中‘|’就是管道,其作用就是将 ps 命令的结果写入管道文件,然后 grep 再从管道文件中读出该数据进行过滤。
你可以用管道操作符I来连接进程。Linux与MS-DOS不同,在Linux下通过管道连接的进程可以同时运行,并且随着数据流在它们之间的传递可以自动地进行协调。举一个简单的例子,你可以使用sort命令对ps命令的输出进行排序。
$ ps >psout.txt
$ sort psout.txt >pssort.out
一个更精巧的解决方案是用管道来连接进程,如下:
$ ps | sort>passort.out
如果想在屏幕上分页显示输出结果,可以再连接第三个进程more,将它们都放在同一个命令行,如下:
$ ps|sort|more
允许连接的进程数目是没有限制的。假设你想看看系统中运行的所有进程的名字,但不包括shell本身,可以使用下面的命令:
$ ps -xo comm |sort |uniq |grep -v sh |more
这个命令首先按字母顺序排序ps命令的输出,再用uniq命令去除名字相同的进程,然后用grep -v
sh命令删除名为sh的进程,最终将结果分页显示在屏幕上。与使用一系列单独的命令并且每个命令都带有自己的临时文件相比,这是一个更精巧的解决方案。但这里有一点 需要引起注意:如果你有一系列的命 令需要执行,相应的输出文件是在这组命令被创建的同时立刻被创建或写入的,所以决不要在命令流中重复使用相同的文件名。如果尝试执行以下命令:
cat mydata.txt |sort |uniq > mydata.txt
最终将得到一个空文件,因为你在读取文件mydata. txt之前就已经覆盖了这个文件的内容。
(1)有名管道
有名管道可以在任意两个进程之间通信
有名管道的创建:
◼ 命令创建: mkfifo FIFO
◼ 系统调用创建
#include <sys/types.h>
#include <sys/stat.h>
-int mkfifo( const char *filename, mode_t mode);
//filename 是管道名 mode 是创建的文件访问权限
-代码演示:
- 第一步:先创建一个有名管道文件——fifo,两个.c文件——write.c和read.c(分别对这个管道文件进行“读”和“写”)。
- 第二步:在write.c中,以“只读”的形式打开有名管道文件“fifo”,打印打开fifo文件得到的文件描述符—-fd,然后不断地将从标准输入——stdin中的内容放入数组——buff中,将buff中的内容write写入与文件描述符fd有关的文件“fifo”中,并且当buff中的前三个字符为“end”时,停止从标准输入中读取内容,直接关闭写端。
- 第三步:在read.c中,以“只读”的形式打开管道文件“fifo”,打印得到的文件描述符——fd,然后将从文件“fifo”中读取的内容放入数组——buff中,再打印到标准输出中,如果读“fifo”时再没有什么数据可读(即写端没有再往文件“fifo”中写入内容),则打印“对方(写端)已关闭”,再跳出关闭读端。
write.c写端:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <string.h>
#include <fcntl.h>
int main()
int fd = open("FIFO", O_WRONLY);
assert(fd != -1);
printf("open FIFO success\\n");
while(1)
printf("please input: ");
char buff[128] = 0;
fgets(buff, 128, stdin);
write(fd, buff, strlen(buff) - 1);
if(strncmp(buff, "end", 3) == 0)
break;
close(fd);
exit(0);
read.c读端:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <string.h>
#include <fcntl.h>
int main()
int fd = open("FIFO", O_RDONLY);
assert(fd != -1);
printf("open FIFO success\\n");
while(1)
char buff[128] = 0;
int n = read(fd, buff, 127);
if(n <= 0 || 0 == strncmp(buff, "end", 3))
break;
printf("%s\\n", buff);
close(fd);
exit(0);
./write
./read
总结:
- 1.管道有读端和写端之分,当写端关闭之后,读端read就会返回0,并且随后也关闭。
- 2.阻塞:当读端没有数据可读时,read调用通常会阻塞,即它将暂停进程(读端进程)来等待直到有数据到达为止。但是,这种阻塞没有多大用处,所以read调用就会返回0,写端程序中的“if(n==0)及之后的语句”都是来应对这种阻塞的。
(2)无名管道
无名管道主要应用于父子进程间的通信。
无名管道的创建:
#include <unistd.h>
/*
pipe()成功返回 0,失败返回-1
fds[0]是管道读端的描述符
fds[1]是管道写端的描述符
*/
int pipe( int fds[2]);
代码演示:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <string.h>
int main()
int fd[2];
int res = pipe(fd);
assert( res != -1 );
pid_t pid = fork();
assert( pid != -1 );
if( pid == 0 )
char buff[128] = 0;
read(fd[0], buff, 127);
printf("child read: %s\\n", buff);
else
write(fd[1], "hello", 5);
close(fd[0]);
close(fd[1]);
exit(0);
3、 管道的特点
◼ 无论有名还是无名,写入管道的数据都在内存中
◼ 管道是一种半双工通信方式(通信方式有单工、半双工、全双工)
◼ 有名和无名管道的区别:有名可以在任意进程间使用,而无名主要在父子进程间
管道的实现:
以上是关于Linux进程间通信管道的主要内容,如果未能解决你的问题,请参考以下文章