在上次的博客中,我给大家介绍了进程间通讯的方式-有名管道。管道分为有名管道和无名管道,那么此次我将给大家介绍一下另一种管道通讯-无名管道。
有名管道是可以应用于任何两个进程之间数据的单向传递,而无名管道是相对于有名管道的,无名管道在使用时产生,不使用后释放,并不会在系统上留下任何痕迹。
无名管道因其使用前没有任何的标示,所以它只能应用于父子进程之间。原因是:调用fork函数父进程产生子进程后,子进程会通过浅拷贝的方式复制父进程的文件表数组,所以父进程和子进程可以通过同一指针访问同一内存区域。
无名管道的操作:
创建:int pipe(int fd[2]),其中fd[0]代表的是读操作,fd[1]代表的是写操作
打开:int pipe(int fd[2])
读 :read(fd[0],buff,size)
写 :write(fd[1],buff,len)
关闭:close(fd[0])--关闭读操作
close(fd[1])--关闭写操作
注意:只要是管道通信都是半双工通讯,而无名管道创建后,父进程在fork产生了子进程后,两个进程分别有一对读写,所以,要在父子进程分别关闭读写。如果在父进程中关闭读操作,那么在子进程中就应该关闭写操作,反之亦然。
下面请看例题:A 进程负责循环接受用户输入的数据,以”end”为结束标志,B 进程负责统计用户输入的单词个数。显示到界面上。要求用无名管道的方式实现。
代码如下:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <assert.h>
#include <memeory.h>
int main()
{
int fd[2];//生成fd数组
pipe(fd);//调用生成无名管道函数pipe
pid_t pid=fork();//创建进程
assert(pid!=-1);
if(pid==0)//子进程读取数据
{
int num=0;
close(fd[1]);
char buff[128]={0};
while(1)
{
read(fd[0],buff,127);//读数据
num+=strlen(buff);
if(strncmp(buff,"end",3)==0)//判断end结尾
{
break;
}
printf("num=%d\n",num);
memset(buff,0,strlen(buff));//清空buff
}
close(fd[0]);
}
else//父进程写入数据
{
close(fd[0]);
printf("please input:");
while(1)
{
char buff1[128]={0};
fgets(buff1,128,stdin);
write(fd[1],buff,strlen(buff)-1);//写入数据
if(strncmp(buff,"end",3)==0)
{
break;
}
}
close(fd[1]);
}
}
测试文件:
据上图测试代码所示,用户可以循环输入,且可以显示总共输入的数据个数,当输入的数据为end时,程序结束。