前面我们讲了进程间通信的一种方式,共享内存。下面看一看另一种机制,匿名管道。
1.什么是管道
管道是一个进程的数据流到另一个进程的通道,即一个进程的数据输出作为另一个进程的数据输入,管道起到了桥梁的作用。
比如,在shell中输入命令:ls -l|grep string,ls和grep是两个进程,"|"符号表示管道,意思是执行ls -l进程,并将输出结果result_1,作为grep string进程的输入result_0,grep进程将result_0中存在字符串string的信息打印到屏幕。

2.管道的使用
1)popen函数:启用一个新进程,并可以向它传递数据,或者通过它接受数据。

FILE *popen(const char *command,conse char *open_mode);

command:运行的程序名和参数
open_mode:有两个值"r(只读)","w(只写)"
      "r":可以获取新进程的输出
      "w":可以向新进程发送数据
返回值:返回输入输出文件流指针

2)pclose函数:关闭输入输出文件流指针
若调用该函数时,新进程仍然在运行,则pclose将等待,直至新进程结束。
返回值:返回新进程的退出码。

3.popen函数使用示例
下例循环读取read_fp输出文件流的内容,写入write_fp的输入文件流,直到输出流内容读完。

#include<stdlib.h>
#include<stdio.h>
#include<string.h>
int main()
{
FILE *read_fp = NULL;
FILE *write_fp = NULL;
char buffer[BUFSIZ+];
int chars_read = ; //初始化缓冲区
memset(buffer,'\0',sizeof(buffer));
read_fp = popen("ls -l","r");
write_fp = popen("grep rwxrwxr-x","w");
if(read_fp && write_fp)
{ chars_read = fread(buffer,sizeof(char),BUFSIZ,read_fp);
while(chars_read)
{
buffer[chars_read]='\0';
//把数据写入grep进程
fwrite(buffer,sizeof(char),chars_read,write_fp);
chars_read = fread(buffer,sizeof(char),BUFSIZ,read_fp);
}
//关闭文件流
pclose(read_fp);
pclose(write_fp);
exit(EXIT_SUCCESS);
}
printf("%d\n",);
exit(EXIT_FAILURE);
}

输出结果:

3、popen的原理及优缺点
当调用popen运行一个新进程时,它首先启动shell,然后将command参数传递给它。
优点:可以使用shell来分析命令字符串,启动非常复杂的shell命令。
缺点:不仅要启动一个新进程,还要启动一个shell,效率会比较低。

4.pipe函数的使用

int pipe(int file_description[]);

file_description[2]:表示管道的输出输入端,输出端数据经过管道流到输入端,函数执行完后, 会将这个数组赋值。
          file_description[1]表示管道输出端文件描述符
          file_description[0]表示管道输入端文件描述符
返回值:0成功,-1失败

与popen不同的是,pipe函数是一个底层调用,不会启动shell。
popen是使用文件流(FILE)工作的,pipe使用的是文件描述符,相应的数据要用底层的read和write来读取和发送。

5.pipe函数使用示例
下例中,我们在父进程中创建一个管道,然后调用fork创建一个子进程。
此时,父进程的file_description[1]输出端,对应着子进程file_description[0]的输入端。
数据通过管道由父进程传到子进程。示例如下:

#include<stdlib.h>
#include<stdio.h>
#include<string.h>
int main()
{
int data_processed = ;
const char data[]="Hello pipe!";
char buffer[BUFSIZ+];
pid_t pid;
memset(buffer,'\0',sizeof(buffer));
int filedes[];
if(pipe(filedes)==)
{
//创建管道成功
//fork子进程
pid=fork();
if(pid==-)
{
fprintf(stderr,"Fork failure");
exit(EXIT_FAILURE);
}
if(pid==)
{
data_processed = read(filedes[],buffer,BUFSIZ);
printf("read %d bytes:%s\n",data_processed,buffer);
exit(EXIT_SUCCESS);
}
else
{
data_processed = write(filedes[],data,strlen(data));
printf("wrote %d bytes:%s\n",data_processed,data);
exit(EXIT_SUCCESS);
}
}
exit(EXIT_FAILURE);
}

输出结果:

6.管道用作标准输入和输出
我们知道标准的输入描述符为0,输出描述符为1,
为了使用已经定义好的标准程序,如od命令,从标准输入读入数据。
需要将管道的输入端描述符置为0,此时,我们需要用到一个辅助函数dup

dup函数:创建一个描述符,复制原有描述符参数的结构到新建的描述符。

int dup(int file_descriptor);

新的描述符规则是,使用最小的可用值。

要想使管道的输入描述符为标准输入描述符,我们可以先关闭文件描述符0,然后调用dup,
此时新建的描述符即为最小可用值0,标准输入描述符。

close();
dup(file_description[]);

上例使用标准输入描述符改造后的示例如下:

#include<stdlib.h>
#include<stdio.h>
#include<string.h>
int main()
{
int data_processed = ;
const char data[]="Hello pipe!";
int filedes[];
pid_t pid;
if(pipe(filedes)==)
{
pid = fork();
if(pid==-)
{
fprintf("stderr","fork failure!\n");
exit(EXIT_FAILURE);
}
if(pid==)
{
close();
dup(filedes[]);
close(filedes[]);
close(filedes[]);
execlp("od","od","-c",);
exit(EXIT_FAILURE);
}
else
{
close(filedes[]);
data_processed = write(filedes[],data,strlen(data));
close(filedes[]);
printf("wrote %d bytes:%s\n",data_processed,data);
}
}
}

输出结果:

7.匿名管道需要注意的问题
1)当管道没有关闭时,若没有数据可读,read调用会阻塞
2)当管道关闭时,read调用会返回0
3)匿名管道通信,进程间必须是父子关系。

Linux进程间通信-匿名管道的更多相关文章

  1. Linux - 进程间通信 - 匿名管道

    一.概念:进程间通信( IPC,InterProcess Communication) 每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进城之间要交换数据必须通过内 ...

  2. Linux学习笔记(12)-进程间通信|匿名管道

    Linux的进程间通信有几种方式,包括,管道,信号,信号灯,共享内存,消息队列和套接字等-- 现在一个个的开始学习! ----------------------------------------- ...

  3. Linux进程间通信(一) - 管道

    管道(pipe) 普通的Linux shell都允许重定向,而重定向使用的就是管道. 例如:ps | grep vsftpd .管道是单向的.先进先出的.无结构的.固定大小的字节流,它把一个进程的标准 ...

  4. Linux 进程间通信(二) 管道

    Linux 进程间通信-管道 进程是一个独立的资源分配单位,不同进程之间的资源是相互独立的,没有关联,不能在一个进程中直接访问另一个进程中的资源.但是,进程不是孤立的,不同的进程之间需要信息的交换以及 ...

  5. Linux进程间通信-命名管道

    前面我们讲了进程间通信的一种方式,匿名管道.我们知道,匿名管道只能用于父子关系的进程之间.那么没有这种关系的进程之间该如何进行数据传递呢? 1.什么是命名管道 匿名管道是在缓存中开辟的输出和输入文件流 ...

  6. Linux进程间通信之管道(pipe)、命名管道(FIFO)与信号(Signal)

    整理自网络 Unix IPC包括:管道(pipe).命名管道(FIFO)与信号(Signal) 管道(pipe) 管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有管道 ...

  7. Linux进程间通信之管道

    1,进程间通信 (IPC ) Inter-Process Communication 比较好理解概念的就是进程间通信就是在不同进程之间传播或交换信息. 2,linux下IPC机制的分类:管道.信号.共 ...

  8. Linux -- 进程间通信之管道

    管道是 Linux 里的一种文件类型,同时也是 Linux 系统下进程间通信的一种方式   创建一个管道文件有两种方式:  Shell 下命令 mkfifo + filename,即创建一个有名管道 ...

  9. linux进程间通信-有名管道(FIFO)

    有名管道(FIFO) 命名管道也被称为FIFO文件,是一种特殊的文件.由于linux所有的事物都可以被视为文件,所以对命名管道的使用也就变得与文件操作非常统一. (1)创建命名管道 用如下两个函数中的 ...

随机推荐

  1. stm32的串口接收字符串以十六进制数

      #include "pbdata.h"   uint8_t TxBuffer1[] = "USART Interrupt Example: This isUSART1 ...

  2. TCP协议三次握手过程分析【图解,简单清晰】

    转自:http://www.cnblogs.com/rootq/articles/1377355.html TCP(Transmission Control Protocol) 传输控制协议 TCP是 ...

  3. hive 中 union all

    hive 中的union all是不能在sql语句的第一层使用的,否则会报 Top level UNION is not supported currently 错误: 例如如下的方式: select ...

  4. bootstrap菜单完美解决---原创

    由于bootstrap的各方优点,偶的“点金项目细化分包管理平台”决定采用它.但在使用中遇到了一些问题,比如菜单的问题,这个菜单是用的一个JQuery的一个效果,点击后,所点击的链接处的class要加 ...

  5. React Native之生命周期

    React Native生命周期主要分为三大阶段:实例化阶段(图中上框部分),存在阶段(图中左框部分),销毁阶段(图中右框部分). 如图: 下面简单讲解一下三大阶段中各自的函数: 实例化阶段: 在日常 ...

  6. NSNotificationCenter 的详细说明

    1. 定义一个方法 -(void) update{       } 2. 对象注册,并关连消息 [[NSNotificationCenter defaultCenter] addObserver:se ...

  7. 7、C#基础整理(类)

    String类 概念:是一个class类型的类,里面包含许多处理字符串的方法和属性 1.length方法. 例: string s = "hello"; Console.Write ...

  8. strlen和mb_strlen的区别

    在php中常见的计算字符串长度的函数有:strlen和mb_strlen.当字符全是英文字符的时候,两者是一样.这里主要比较一下,中英文混排的时候,两个计算结果. 在PHP中,strlen与mb_st ...

  9. 常用的php字符串处理函数

    php常用的字符串处理函数 1.trim():从字符串的两端删除空白字符和其他预定义字符 ltrim():从字符串的左端删除空格和其他预定义字符 rtrim():从字符串的末端开始删除空白字符和其他预 ...

  10. Magento控制器

    提到模型-视图-控制器这种MVC架构,要追溯到Smalltalk编程语言和Xerox Parc.从那个时候开始,就有许多系统将自己描述为MVC架构.这些系统虽然在某些地方有细微差别,但都实现了数据层, ...