linux popen管道,详解linux进程间通信-管道 popen函数 dup2函数

前言:进程之间交换信息的唯一方法是经由fo r k或e x e c传送打开文件,或通过文件系统。本章将说明进程之间相互通信的其他技术—I P C(InterProcessCommunication)。今天将介绍半双工的管道。

一、匿名管道

1、匿名管道介绍:

管道有两种限制;

(1) 它们是半双工的。数据只能在一个方向上流动。

(2)它们只能在具有公共祖先的进程之间使用。通常,一个管道由一个进程创建,然后该进程调用fo r k,此后父、子进程之间就可应用该管道。

管道是由调用p i p e函数而创建的:

#include

int pipe(intf i l e d e s [ 2 ]) ;

返回:若成功则为0,若出错则为 - 1

经由参数f i l e d e s返回两个文件描述符: f i l e d e s [ 0 ]为读而打开, f i l e d e s [ 1 ]为写而打开。 f i l e d e s [ 1 ]

的输出是f i l e d e s [ 0 ]的输入。

程序1- 1创建了一个从父进程到子进程的管道,并且父进程经由该管道向子进程传送数据。

#include "my.h"

int main()

{

int pfd[2],ret;

ret = pipe(pfd);//创建管道

if(ret<0)

{

perror("pipe error!");

exit(-1);

}

pid_t pid = fork();

if(pid<0)

{

perror("fork error!");

exit(-1);

}

else if(pid>0)//父进程

{

close(pfd[0]);

int num;

puts("please input your num:");

scanf("%d",&num);

write(pfd[1],&num,sizeof(num));

//wait(NULL);

}

else //子进程

{

close(pfd[1]);

int num;

read(pfd[0],&num,sizeof(num));

printf("num:%d\n",num);

}

return 0;

}

注:头文件my.h见这篇博客:http://www.cnblogs.com/liudw-0215/p/8946879.html

运行示例,如下图:

0569fd65a9b6f3851d6fff91807b880a.png

接下来介绍几个跟管道有关的函数。

2、dup和d u p 2函数

下面两个函数都可用来复制一个现存的文件描述符:

#include

int dup(intf i l e d es) ;

int dup2(int f i l e d e s, int f i l e d e s 2) ;

两函数的返回:若成功为新的文件描述符,若出错为- 1

由d u p返回的新文件描述符一定是当前可用文件描述符中的最小数值。用 d u p 2则可以用f i l e d e s 2

参数指定新描述符的数值。如果 f i l e d e s 2已经打开,则先将其关闭。如若f i l e d e s等于f i l e d e s 2,则

d u p 2返回f i l e d e s 2,而不关闭它。

优化程序1-1,程序1-2如下:

#include "my.h"

int main()

{

int pfd[2],ret;

ret = pipe(pfd);

if(ret<0)

{

perror("pipe error!");

exit(-1);

}

pid_t pid = fork();

if(pid<0)

{

perror("fork error!");

exit(-1);

}

else if(pid>0)

{

close(pfd[0]);

int num;

puts("please input your num:");

scanf("%d",&num);

write(pfd[1],&num,sizeof(num));

wait(NULL);

}

else

{

close(pfd[1]);

dup2(pfd[0],STDIN_FILENO);//pfd[0]复制到标准输入

int num;

read(STDIN_FILENO,&num,sizeof(num));

printf("num:%d\n",num);

}

return 0;

}

3、popen和p c l o s e函数

因为常见的操作是创建一个连接到另一个进程的管道,然后读其输出或向其发送输入,所

以标准I / O库为实现这些操作提供了两个函数 p o p e n和p c l o s e。这两个函数实现的操作是:创建

一个管道, f o r k一个子进程,关闭管道的不使用端, e x e c一个s h e l l以执行命令,等待命令终止。

#include

FILE *popen(const char * c m d s t r i n g, const char * t y p e) ;

返回:若成功则为文件指针,若出错则为 N U L L

int pclose(FILE * f p) ;

返回: c m d s t r i n g的终止状态,若出错则为 - 1

函数popen 先执行f o r k,然后调用e x e c以执行c m d s t r i n g,并且返回一个标准 I / O文件指针。

如果t y p e是"r",则文件指针连接到c m d s t r i n g的标准输出。

如果t y p e 是"w",则文件指针连接到c m d s t r i n g 的标准输入。

程序1-3将用popen函数实现下图功能:

d0cd1b84ecae8c099e57c7a04bcc4e94.png

#include "my.h"

int main()

{

int c;

while((c = getchar()) != EOF)

{

if(isupper(c))  //是否有大写

c = tolower(c);  //转为小写

if(putchar(c) == EOF)

puts("put error!");

if(c == '\n')

fflush(stdout);  //刷新标准输出

}

exit(0);

}

---isupper.c---

#include "my.h"

#define MAXLINE 4096

int main()

{

char line[MAXLINE];

FILE *fpin;

if((fpin = popen("./upper","r")) == NULL)

perror("popen error!");

for(;;){

fputs("prompt > ",stdout);

fflush(stdout);

if(fgets(line,MAXLINE,fpin) == NULL)

break;

if(fputs(line,stdout) == EOF)

perror("puts error!");

}

if(pclose(fpin) == -1)

perror("pclose error!");

putchar('\n');

return 0;

}

---popen.c---

运行演示如下图:

323d65eee6bd3e99eb938f791bbb79d5.png

二、有名管道(命名管道)

1、简介

命名管道有时被称为FIFO。管道只能由相关进程使用,它们共同的祖先进程创建了管道。

但是,通过F I F O,不相关的进程也能交换数据。#include

#include

int mkfifo(const char * p a t h n a m e, mode_tm o d e) ;

返回:若成功则为0,若出错则为 - 1

m k f i f o函数中m o de参数的规格说明与o p e n函数中的m o d e相同。一旦已经用 m k f i f o创建了一个 F I F O,就可用 o p e n打开它。确实,一般的文件 I / O函数

(c l o s e、r e a d、w r i t e、u n l i n k等)都可用于F I F O。

程序2-1演示有名管道通信,一个写端、一个读端:

#include "my.h"

typedef struct{

char name[16];

int age;

double height;

}Person;

int main()

{

mkfifo("pipe",0644);//创建管道 名字为pipe

int fd = open("pipe",O_WRONLY);

if(fd < 0)

{

perror("open error!");

exit(-1);

}

Person p;

puts("please input your name,age,height:");

scanf("%s%d%lf",p.name,&p.age,&p.height);

write(fd,&p,sizeof(p));

close(fd);

return 0;

}

---fwrite.c---

#include "my.h"

typedef struct{

char name[16];

int age;

double height;

}Person;

int main()

{

int fd = open("pipe",O_RDONLY);

if(fd < 0)

{

perror("open error!");

exit(-1);

}

Person p;

read(fd,&p,sizeof(p));

printf("name:%-5sage:%-5dheight:%-5lf\n ",p.name,p.age,p.height);

close(fd);

unlink("pipe");//删除管道文件

return 0;

}

--- fread.c ---

运行演示:先编译fwrite.c生成w可执行用户,./w执行,再编译fread.c然后执行,写端输入数据,读端输出数据:

2cae405f30c4786dd0bbf5b10b1e9a44.png

6b09fb50313a3c6d8d6b2a4dcc7ac854.png

总结:主要介绍了进程间通信的管道,主要分为匿名管道和有名管道,还介绍了popen等函数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值