在Linux中,管道是一种使用非常频繁的通信机制。从本质上说,管道也是一种文件,但它又和一般的文件有所不同,管道可以克服使用文件进行通信的两个问题,具体表现为:
· 限制管道的大小。实际上,管道是一个固定大小的缓冲区。在Linux中,该缓冲区的大小为1页,即4K字节,使得它的大小不像文件那样不加检验地增长。使用单个固定缓冲区也会带来问题,比如在写管道时可能变满,当这种情况发生时,随后对管道的write()调用将默认地被阻塞,等待某些数据被读取,以便腾出足够的空间供write()调用写。
· 读取进程也可能工作得比写进程快。当所有当前进程数据已被读取时,管道变空。当这种情况发生时,一个随后的read()调用将默认地被阻塞,等待某些数据被写入,这解决了read()调用返回文件结束的问题。
注意:从管道读数据是一次性操作,数据一旦被读,它就从管道中被抛弃,释放空间以便写更多的数据。
我们可以使用管道符|来连接进程.在Linux系统中,由管道连接起来的进程可以自动运行,就如同在他们有一个数据流一样.在下面的这个例子中,我们要使用sort命令来排序ps的输出.而如果我们不使用管道,我们就要分几步来完成:
$ ps > psout.txt
$ sort psout.txt >pssort.out
一个更好的办法就是可以用管道来处理:
$ ps | sort > pssort.out
因为我们要在屏幕上看到他们,我们要使用第三个进程:
$ ps | sort | more
使用的管道数并没有一个量的限制.如果我们要看到正在运行的除了shell以外的不同名字的进程,我们可以用下面的命令:
$ ps -xo comm | sort | uniq | grep -v sh | more
在这个命令中,使用了ps的输出,将这个输出以字母的顺序进行排序,使用uniq来解压进程,使用grep -v sh来移除名为sh的进程,最后在屏幕上显示结果.
在这里我们就可以看到,这样的方式式要比单个执行的命令好得多.在这里我们要注意的一点点就是,在这个命令中我们不要两次使用同一个文件.如下面的命令:
$ cat mydate.txt | sort | uniq | >mydate.txt
这样我们就会得到一个空文件,因为在我们读取这个之前已经改写了这个文件. Linux C 中的管道函数pipe
#include <unistd.h>
函数原型: int pipe(int fd[2])
返回值: 成功为 0 , 出错为 -1
管道只能用于有亲缘关系进程间的通信。要实现独立进程间的通信可参照有名管道(FIFO)。 用unix所谓的管道 可以把一个进程的标准输出流与另一个进程的标准输入流连接起来
unix中许多命令被设计为过滤器 从标准输入中读取输入 将输出传送到 标准输出
bash用“|” 在两个命令之间创建管道 管道只能半双工通信,即某一时刻只能单向传输。要实现父子进程双方互动通信,需要定义两个管道。
下面只提供单一管道父进程向子进程发送“Hello!”。 /*使用pipe实现父进程向子进程发送信息*/#include<stdio.h>#include<unistd.h>#include<stdlib.h>intmain(){intfd[2];pipe(fd);//创建管道pid_tchild;child=fork();//创建子进程charbuff[15];//子进程用于读取的缓冲区chardata[]=Hello!;//父进程用于写入的数据if(child==-1)//出错处理{perror(Child:);exit(1);}elseif(child==0)//子进程从管道中读取信息到buff{close(fd[1]);if(read(fd[0],buff,15)>0){printf(pid=%d\tppid=%d\t|%s\t<Read>\n,getpid(),getppid(),buff);}close(fd[0]);exit(0);}else//父进程通过data向管道中写入信息{close(fd[0]);if(write(fd[1],data,15)>0){printf(pid=%d\tppid=%d\t|%s\t<Write>\n,getpid(),getppid(),data);}close(fd[1]);exit(0);}waitpid(child,NULL,0);//等待子进程结束exit(0);}