linux利用管道实现进程通信,Linux通过匿名管道进行进程间通信( 二 )


exit();
exit();
运行结果如下:
从运行结果来看 , 达到了信息筛选的目的 。程序在进程ls中读取数据 , 再把数据发送到进程grep中进行筛选处理 , 相当于在shell中直接输入命令:ls -l | grep -x 。
3、popen的实现方式及优缺点
当请求popen调用运行一个程序时 , 它首先启动shell , 即系统中的sh命令 , 然后将字符串作为一个参数传递给它 。
这样就带来了一个优点和一个缺点 。优点是:在Linux中所有的参数扩展都是由shell来完成的 。所以在启动程序(中的命令程序)之前先启动shell来分析命令字符串 , 也就可以使各种shell扩展(如通配符)在程序启动之前就全部完成 , 这样我们就可以通过popen启动非常复杂的shell命令 。
而它的缺点就是:对于每个popen调用 , 不仅要启动一个被请求的程序 , 还要启动一个shell , 即每一个popen调用将启动两个进程 , 从效率和资源的角度看 , popen函数的调用比正常方式要慢一些 。
三、pipe调用
如果说popen是一个高级的函数 , pipe则是一个底层的调用 。与popen函数不同的是 , 它在两个进程之间传递数据不需要启动一个shell来解释请求命令 , 同时它还提供对读写数据的更多的控制 。
pipe函数的原型如下:
#
int pipe(int [2]);
我们可以看到pipe函数的定义非常特别 , 该函数在数组中墙上两个新的文件描述符后返回0 , 如果返回返回-1 , 并设置errno来说明失败原因 。
数组中的两个文件描述符以一种特殊的方式连接起来 , 数据基于先进先出的原则 , 写到[1]的所有数据都可以从[0]读回来 。由于数据基于先进先出的原则 , 所以读取的数据和写入的数据是一致的 。
特别提醒:
1、从函数的原型我们可以看到 , 它跟popen函数的一个重大区别是 , popen函数是基于文件流(FILE)工作的 , 而pipe是基于文件描述符工作的 , 所以在使用pipe后 , 数据必须要用底层的read和write调用来读取和发送 。
2、不要用[0]写数据 , 也不要用[1]读数据 , 其行为未定义的 , 但在有些系统上可能会返回-1表示调用失败 。数据只能从[0]中读取 , 数据也只能写入到[1] , 不能倒过来 。
例子:
首先 , 我们在原先的进程中创建一个管道 , 然后再调用fork创建一个新的进程 , 最后通过管道在两个进程之间传递数据 。源文件名为pipe.c , 代码如下:
#
#
#
#
int main()
int= 0;
int [2];
const char data[] = "Hello pipe!";
char [ + 1];
pid_t pid;
//清空缓冲区
(, '\0', ());
if(pipe() == 0)
//创建管道成功
//通过调用fork创建子进程
pid = fork();
if(pid == -1)
(, "Fork ");
exit();
if(pid == 0)
//子进程中
//读取数据
= read([0], , );
("Read %d bytes: %s\n", , );
exit();
else
//父进程中
//写数据
= write([1], data, (data));
("Wrote %d bytes: %s\n", , data);
//休眠2秒 , 主要是为了等子进程先结束 , 这样做也只是纯粹为了输出好看而已
//父进程其实没有必要等等子进程结束
sleep(2);
exit();
exit();
运行结果为:
可见 , 子进程读取了父进程写到[1]中的数据 , 如果在父进程中没有sleep语句 , 父进程可能在子进程结束前结束 , 这样你可能将看到两个输入之间有一个命令提示符分隔 。