在上一篇《有名管道通信》中,介绍了有名管道通信,相对于有名管道通信而言,今天说一下无名管道通信。
有名管道通信在文件目录树中有标示,而无名管道通信是没有标示的。相对于有名管道而言,无名管道在使用时产生,使用后释放,并不会在系统上留下任何痕迹。正是由于这一特点,无名管道通信是有限制的,只能应用于父子进程之间。因为子进程是复制父进程的文件表数组(浅拷贝)。
无名管道操作:
1、创建/打开:int pipe(int fd[2]);
看到pipe函数的参数会有点奇怪,我们都知道数组传进来会退化成指针,2在这里是没有什么实际作用的。在这里只是想说明数组2个元素就够了,fd[0]表示读,fd[1]表示写。成功返回0,失败返回-1。
2、读:int read(fd[0],char*buff,int size);
上边的数组fd[0]、fd[1]也就是文件描述符,这样它的读、写、关闭和文件是一样的。
3、写:int write(fd[1],char*buff,int size);
4、关闭:int close(fd[0]);
int close(fd[1]);
由于数组有2个元素,只读打开一个,只写打开一个,所以要关闭两次。父子进程中调用pipe函数时,父进程打开两个,子进程打开两个,由于管道通信都是半双工通信,只需要一个读或写就可以,所以在无名管道创建,fork出子进程后需要关闭一个。父子进程需配合着来,如果父进程关读,那么子进程就关写;如果父进程关写,那么子进程就关读。
下面就看一个简单的例子:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<fcntl.h>
int main()
{
int fd[2] = {0};
pipe(fd);
int pid = fork();
if(pid == 0)
{
close(fd[0]);
while(1)
{
printf("please input:");
fflush(stdout);
char buff[128] = {0};
fgets(buff,127,stdin);
write(fd[1],buff,strlen(buff)-1);
if(strcmp(buff,"end") == 0)
{
break;
}
}
close(fd[1]);
exit(0);
}
else
{
close(fd[1]);
int num = 0;
while(1)
{
char buff[128] = {0};
read(fd[0],buff,127);
num += strlen(buff);
if(strcmp(buff,"end") == 0)
{
break;
}
printf("num=%d,strlen=%d\n",num,strlen(buff));
}
close(fd[0]);
exit(0);
}
}
其运行结果如下图所示: