linux进程文件描述符与管道,Linux进程间通信-匿名管道(示例代码)

前面我们讲了进程间通信的一种方式,共享内存。下面看一看另一种机制,匿名管道。

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#include#include

intmain()

{

FILE*read_fp =NULL;

FILE*write_fp =NULL;char buffer[BUFSIZ+1];int chars_read = 0;//初始化缓冲区

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",2);

exit(EXIT_FAILURE);

}

输出结果:

20180110193145311022.png

3、popen的原理及优缺点

当调用popen运行一个新进程时,它首先启动shell,然后将command参数传递给它。

优点:可以使用shell来分析命令字符串,启动非常复杂的shell命令。

缺点:不仅要启动一个新进程,还要启动一个shell,效率会比较低。

4.pipe函数的使用

int pipe(int file_description[2]);

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#include#include

intmain()

{int data_processed = 0;const char data[]="Hello pipe!";char buffer[BUFSIZ+1];

pid_t pid;

memset(buffer,‘\0‘,sizeof(buffer));int filedes[2];if(pipe(filedes)==0)

{//创建管道成功//fork子进程

pid=fork();if(pid==-1)

{

fprintf(stderr,"Fork failure");

exit(EXIT_FAILURE);

}if(pid==0)

{

data_processed= read(filedes[0],buffer,BUFSIZ);

printf("read %d bytes:%s\n",data_processed,buffer);

exit(EXIT_SUCCESS);

}else{

data_processed= write(filedes[1],data,strlen(data));

printf("wrote %d bytes:%s\n",data_processed,data);

exit(EXIT_SUCCESS);

}

}

exit(EXIT_FAILURE);

}

输出结果:

20180110193145313952.png

6.管道用作标准输入和输出

我们知道标准的输入描述符为0,输出描述符为1,

为了使用已经定义好的标准程序,如od命令,从标准输入读入数据。

需要将管道的输入端描述符置为0,此时,我们需要用到一个辅助函数dup

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

int dup(int file_descriptor);

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

要想使管道的输入描述符为标准输入描述符,我们可以先关闭文件描述符0,然后调用dup,

此时新建的描述符即为最小可用值0,标准输入描述符。

close(0);

dup(file_description[0]);

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

#include#include#include

intmain()

{int data_processed = 0;const char data[]="Hello pipe!";int filedes[2];

pid_t pid;if(pipe(filedes)==0)

{

pid=fork();if(pid==-1)

{

fprintf("stderr","fork failure!\n");

exit(EXIT_FAILURE);

}if(pid==0)

{

close(0);

dup(filedes[0]);

close(filedes[0]);

close(filedes[1]);

execlp("od","od","-c",0);

exit(EXIT_FAILURE);

}else{

close(filedes[0]);

data_processed= write(filedes[1],data,strlen(data));

close(filedes[1]);

printf("wrote %d bytes:%s\n",data_processed,data);

}

}

}

输出结果:

20180110193145334460.png

7.匿名管道需要注意的问题

1)当管道没有关闭时,若没有数据可读,read调用会阻塞

2)当管道关闭时,read调用会返回0

3)匿名管道通信,进程间必须是父子关系。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值