pipe我们用中文叫做管道。

以下讲解均是基于Linux为环境:

函数简介

所需头文件 #include

函数原型 int pipe(int fd[2])

函数传入值 fd[2]:管道的两个文件描述符,之后就是可以直接操作这两个文件描述符

返回值 成功 0 失败 -1

什么是管道

管道是Linux 支持的最初Unix IPC形式之一,具有以下特点:

管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道; 只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程); 单独构成一种独立的文件系统:管道对于管道两端的进程而言,就是一个文件,但它不是普通的文件,它不属于某种文件系统,而是自立门户,单独构成一种文件系统,并且只存在与内存中。 数据的读出和写入:一个进程向管道中写的内容被管道另一端的进程读出。写入的内容每次都添加在管道缓冲区的末尾,并且每次都是从缓冲区的头部读出数据。

管道的创建

#include

int pipe(int fd[2])

该函数创建的管道的两端处于一个进程中间,在实际应用中没有太大意义,因此,一个进程在由pipe()创建管道后,一般再fork一个子进程,然后通过管道实现父子进程间的通信(因此也不难推出,只要两个进程中存在亲缘关系,这里的亲缘关系指的是具有共同的祖先,都可以采用管道方式来进行通信)。

管道的读写规则

管道两端可分别用描述字fd[0]以及fd[1]来描述,需要注意的是,管道的两端是固定了任务的。即一端只能用于读,由描述字fd[0]表示,称其为管道读端;另一端则只能用于写,由描述字fd[1]来表示,称其为管道写端。如果试图从管道写端读取数据,或者向管道读端写入数据都将导致错误发生。一般文件的I/O函数都可以用于管道,如close、read、write等等。

从管道中读取数据:

如果管道的写端不存在,则认为已经读到了数据的末尾,读函数返回的读出字节数为0; 当管道的写端存在时,如果请求的字节数目大于PIPE_BUF,则返回管道中现有的数据字节数,如果请求的字节数目不大于PIPE_BUF,则返回管道中现有数据字节数(此时,管道中数据量小于请求的数据量);或者返回请求的字节数(此时,管道中数据量不小于请求的数据量)。注:(PIPE_BUF在include/linux/limits.h中定义,不同的内核版本可能会有所不同。Posix.1要求PIPE_BUF至少为512字节,red hat 7.2中为4096)。

关于管道的读规则验证:

/**************

* readtest.c *

**************/

#include

#include

#include

main()

{

int pipe_fd[2];

pid_t pid;

char r_buf[100];

char w_buf[4];

char* p_wbuf;

int r_num;

int cmd;

memset(r_buf,0,sizeof(r_buf));

memset(w_buf,0,sizeof(r_buf));

p_wbuf=w_buf;

if(pipe(pipe_fd)<0)

{

printf("pipe create error ");

return -1;

}

if((pid=fork())==0)

{

printf(" ");

close(pipe_fd[1]);

sleep(3);//确保父进程关闭写端

r_num=read(pipe_fd[0],r_buf,100);

printf( "read num is %d the data read from the pipe is %d ",r_num,atoi(r_buf));

close(pipe_fd[0]);

exit();

}

else if(pid>0)

{

close(pipe_fd[0]);//read

strcpy(w_buf,"111");

if(write(pipe_fd[1],w_buf,4)!=-1)

printf("parent write over ");

close(pipe_fd[1]);//write

printf("parent close fd[1] over ");

sleep(10);

}

}

/**************************************************

* 程序输出结果:

* parent write over

* parent close fd[1] over

* read num is 4 the data read from the pipe is 111

* 附加结论:

* 管道写端关闭后,写入的数据将一直存在,直到读出为止.

****************************************************/

向管道中写入数据:

向管道中写入数据时,linux将不保证写入的原子性,管道缓冲区一有空闲区域,写进程就会试图向管道写入数据。如果读进程不读走管道缓冲区中的数据,那么写操作将一直阻塞。

注:只有在管道的读端存在时,向管道中写入数据才有意义。否则,向管道中写入数据的进程将收到内核传来的SIFPIPE信号,应用程序可以处理该信号,也可以忽略(默认动作则是应用程序终止)。

对管道的写规则的验证1:写端对读端存在的依赖性

#include

#include

main()

{

int pipe_fd[2];

pid_t pid;

char r_buf[4];

char* w_buf;

int writenum;

int cmd;

memset(r_buf,0,sizeof(r_buf));

if(pipe(pipe_fd)<0)

{

printf("pipe create error ");

return -1;

}

if((pid=fork())==0)

{

close(pipe_fd[0]);

close(pipe_fd[1]);

sleep(10);

exit();

}

else if(pid>0)

{

sleep(1); //等待子进程完成关闭读端的操作

close(pipe_fd[0]);//write

w_buf="111";

if((writenum=write(pipe_fd[1],w_buf,4))==-1)

printf("write to pipe error ");

else

printf("the bytes write to pipe is %d ", writenum);

close(pipe_fd[1]);

}

}

则输出结果为: Broken pipe,原因就是该管道以及它的所有fork()产物的读端都已经被关闭。如果在父进程中保留读端,即在写完pipe后,再关闭父进程的读端,也会正常写入pipe,读者可自己验证一下该结论。因此,在向管道写入数据时,至少应该存在某一个进程,其中管道读端没有被关闭,否则就会出现上述错误(管道断裂,进程收到了SIGPIPE信号,默认动作是进程终止)

对管道的写规则的验证2:linux不保证写管道的原子性验证

#include

#include

#include

main(int argc,char**argv)

{

int pipe_fd[2];

pid_t pid;

char r_buf[4096];

char w_buf[4096*2];

int writenum;

int rnum;

memset(r_buf,0,sizeof(r_buf));

if(pipe(pipe_fd)<0)

{

printf("pipe create error ");

return -1;

}

if((pid=fork())==0)

{

close(pipe_fd[1]);

while(1)

{

sleep(1);

rnum=read(pipe_fd[0],r_buf,1000);

printf("child: readnum is %d ",rnum);

}

close(pipe_fd[0]);

exit();

}

else if(pid>0)

{

close(pipe_fd[0]);//write

memset(r_buf,0,sizeof(r_buf));

if((writenum=write(pipe_fd[1],w_buf,1024))==-1)

printf("write to pipe error ");

else

printf("the bytes write to pipe is %d ", writenum);

writenum=write(pipe_fd[1],w_buf,4096);

close(pipe_fd[1]);

}

}

输出结果:

the bytes write to pipe 1000

the bytes write to pipe 1000 //注意,此行输出说明了写入的非原子性

the bytes write to pipe 1000

the bytes write to pipe 1000

the bytes write to pipe 1000

the bytes write to pipe 120 //注意,此行输出说明了写入的非原子性

the bytes write to pipe 0

the bytes write to pipe 0

......

结论:

写入数目小于4096时写入是非原子的!

如果把父进程中的两次写入字节数都改为5000,则很容易得出下面结论:

写入管道的数据量大于4096字节时,缓冲区的空闲空间将被写入数据(补齐),直到写完所有数据为止,如果没有进程读数据,则一直阻塞。

管道应用实例

实例一:用于shell

管道可用于输入输出重定向,它将一个命令的输出直接定向到另一个命令的输入。比如,当在某个shell程序(Bourne shell或C shell等)键入who│wc -l后,相应shell程序将创建who以及wc两个进程和这两个进程间的管道。考虑下面的命令行:

$kill -l 运行结果见 附一。

$kill -l | grep SIGRTMIN 运行结果如下:

30) SIGPWR 31) SIGSYS 32) SIGRTMIN 33) SIGRTMIN+1

34) SIGRTMIN+2 35) SIGRTMIN+3 36) SIGRTMIN+4 37) SIGRTMIN+5

38) SIGRTMIN+6 39) SIGRTMIN+7 40) SIGRTMIN+8 41) SIGRTMIN+9

42) SIGRTMIN+10 43) SIGRTMIN+11 44) SIGRTMIN+12 45) SIGRTMIN+13

46) SIGRTMIN+14 47) SIGRTMIN+15 48) SIGRTMAX-15 49) SIGRTMAX-14

实例二:用于具有亲缘关系的进程间通信

下面例子给出了管道的具体应用,父进程通过管道发送一些命令给子进程,子进程解析命令,并根据命令作相应处理。

#include

#include

main()

{

int pipe_fd[2];

pid_t pid;

char r_buf[4];

char** w_buf[256];

int childexit=0;

int i;

int cmd;

memset(r_buf,0,sizeof(r_buf));

if(pipe(pipe_fd)<0)

{

printf("pipe create error ");

return -1;

}

if((pid=fork())==0)

//子进程:解析从管道中获取的命令,并作相应的处理

{

printf(" ");

close(pipe_fd[1]);

sleep(2);

while(!childexit)

{

read(pipe_fd[0],r_buf,4);

cmd=atoi(r_buf);

if(cmd==0)

{

printf("child: receive command from parent over now child process exit ");

childexit=1;

}

else if(handle_cmd(cmd)!=0)

return;

sleep(1);

}

close(pipe_fd[0]);

exit();

}

else if(pid>0)

//parent: send commands to child

{

close(pipe_fd[0]);

w_buf[0]="003";

w_buf[1]="005";

w_buf[2]="777";

w_buf[3]="000";

for(i=0;i<4;i++)

write(pipe_fd[1],w_buf[i],4);

close(pipe_fd[1]);

}

}

//下面是子进程的命令处理函数(特定于应用):

int handle_cmd(int cmd)

{

if((cmd<0)||(cmd>256))

//suppose child only support 256 commands

{

printf("child: invalid command ");

return -1;

}

printf("child: the cmd from parent is %d ", cmd);

return 0;

}

windows c语言 pipe,pipe 函数 (C语言)相关推荐

  1. c语言掌握常用函数,c语言一些常用函数.pdf

    c语言一些常用函数 C 语言程序设计(常用函数说明) C 语言是 1972 年由美国的 Dennis Ritchie 设计发明的,并首次在 UNIX 操作系统的 DE C PDP-11 计算机上使用. ...

  2. C语言algorithm主函数,C语言中主函数中相关有关问题?

    C语言中主函数中相关问题??? #include #include #include #include #include #include #include #include #include usi ...

  3. c语言 格式转换函数,C语言中的格式转换函数.doc

    C语言中的格式转换函数 C语言中的格式转换函数 表头文件 #include 定义函数 double atof(const char *nptr); 函数说明 atof()会扫描参数nptr字符串,跳过 ...

  4. python语言中有哪些函数_Python语言中的函数

    本文主要向大家介绍了Python语言中的函数,通过具体的内容向大家展示,希望对大家学习Python语言有所帮助. 学了 Python 中的数据类型,语句,接下来就来说一下 Python 中的函数,函数 ...

  5. c语言读取文件函数,C语言文件操作详细分析:读取文件(fread函数使用)

    C语言文件操作详细分析:读取文件(fread函数使用) 这里详细介绍了C语言读取文件的函数fread的使用说明,参照了MSDN的说明,同时加入自己的经验让大家学的更加明白. C语言读取文件函数frea ...

  6. c语言自动排序函数,C语言快速排序函数用法(qsort)

    本文实例为大家分享了C语言快排函数用法,供大家参考,具体内容如下 #include #include #include struct student { int id; char name[12]; ...

  7. C语言 define 定义函数 - C语言零基础入门教程

    目录 一.define 简介 二.define 定义函数 1.define 定义不带参数的函数 2.define 定义带参数的函数 三.define 定义函数陷阱 1.define 函数陷阱一 2.d ...

  8. windows c语言目录操作函数,c语言目录操作在C/C++语言中如何进行目录操作,如得到目录内的 爱问知识人...

    这里给你提供一些C的目录操作函数,原型声明所在头文件为dir.h.dos.h,仅供参考: int chdir(char *path) 使指定的目录path(如:"C:\\WINDOWS&qu ...

  9. c语言 swap交换函数_C语言经典100题(14)

    1 上期答案揭晓 首先给大家看看上一篇文章C语言经典100题(13)中第三部分编程题的答案: #includeint main(){ int i,x,y,z; for(i=100;i<1000; ...

  10. c语言分组求和函数,R语言 实现data.frame 分组计数、求和等

    df为1个data.frame对象,有stratum和psu两列,这里统计stratum列计数 方法1: cnt = table(df$stratum) 方法2: cnt = tapply(df$ps ...

最新文章

  1. Visual Studio中将打开的代码与类文件进行关联
  2. 我的年龄又快被5整除了......
  3. 巨头间未来战争-丰收节交易会·万祥军:农业AI发展概况
  4. 关于Integer.MAX_VALUE + 1 = Integer.MIN_VALUE 问题
  5. BZOJ4881 线段游戏(二分图+树状数组/动态规划+线段树)
  6. 初学Spring Boot
  7. 计算机史上首篇教你从算法问题提炼算法思想的文章
  8. FlashPaper安装及使用方法
  9. 线性表之顺序存储,基本操作
  10. 显示纯服务器_BBT三行代码搭建服务器,让Dynamo跳出IronPython的封锁
  11. 通过截取实时系统日志查找问题bug的小技巧命令--linux
  12. Jquery实现循环删除Reaper某一行
  13. Java车辆管理课程设计_车辆管理信息系统--Java课程设计.doc
  14. C#开发WebService实例和发布
  15. 720-C语言实现2048游戏
  16. 中国电信物联网平台入门学习笔记7:NB-IOT信号如何检测
  17. R语言威尔科克森符号秩和(Wilcoxon Signed Rank statistic)分布
  18. python语言玫瑰花_python 实现漂亮的烟花,樱花,玫瑰花
  19. python程序设计第五章答案_中国大学MOOC第五章单元测试答案_Python程序设计期末答案...
  20. 听《武志红的心理课之潜意识就是命运》有感 命运,这个东西信者有,不信者无。我很赞同武老师的观点,一个热的外在命运和我们的内在想象,是镜像关系。这不禁让我想起了小时候的一个故事:一群青蛙比赛爬山,很多人

热门文章

  1. pikachu漏洞靶机之xss漏洞post提交方式
  2. [网络安全提高班] 一〇一.网络攻防溯源普及和医疗数据安全总结
  3. 搜索引擎和知识图谱那些事 (上).基础篇
  4. 【数据结构与算法】之深入解析“石子游戏III”的求解思路与算法示例
  5. Martix工作室考核题 —— 打印九九乘法表
  6. 数组、字符串及字符串相关函数
  7. 【机器视觉】 break算子
  8. 【linux系统编程】进程间通信:信号中断处理
  9. win10防火墙删除的文件在哪里_Win10系统关闭Windows Defender
  10. python schedule多线程_Python定时任务sched模块用法示例