一、概述
管道是UNIX IPC的最老形式,并且所有U N I X系统都提供此种通信机制,管道有两种限制: (1) 它们是半双工的,数据只能在一个方向上流动。 (2) 它们只能在具有公共祖先的进程之间使用。通常,一个管道由一个进程创建,然后该进程调用fork,此后父、子进程之间就可应用该管道。
管道分为有名管道和无名管道,又可以称为匿名管道和命名管道。
二、无名管道(PIPE)
无名管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用.进程的亲缘关系一般指的是父子关系。无明管道一般用于两个不同进程之间的通信。当一个进程创建了一个管道,并调用fork创建自己的一个子进程后,父进程关闭读管道端,子进程关闭写管道端,这样提供了两个进程之间数据流动的一种方式。当管道的一端被关闭后,下列规则起作用:
1)当读一个写端已被关闭的管道时,在所有数据都被读取后,read返回0,以指示达到了文件结束处。
2)如果写一个读端已被关闭的管道,则产生信号SIGPIPE。如果忽略该信号或者捕捉该信号并从其处理程序返回,则write出错返回,errno设置为EPIPE。
在写管道时,常数PIPE_BUF规定了内核中管道缓存器的大小。如果对管道进行write调用,而且要求写的字节数小于等于PIPE_BUF,则此操作不会与其他进程对同一管道(或 FIFO)的write操作穿插进行。但是,若有多个进程同时写一个管道(或 FIFO),而且某个或某些进程要求写的字节数超过PIPE_BUF字节数,则数据可能会与其他写操作的数据相穿插。
下面程序是创建了一个从父进程到子进程的管道,并且父进程经由该管道向子进程传送数据。
#include<stdio.h>
#include<string.h>
#include<signal.h>
#include<unistd.h>
#include<stdlib.h>
void main()
{
int fd[2]={-1,-1};
//创建管道
if(-1==pipe(fd))
{
printf("创建管道失败\n");
}
//创建子进程
int pid=fork();
if(pid==0)//子进程
{
//获取信息
close(fd[1]);//关闭写端
int result=-1;
char buf[100]="";
while(1)
{
result=read(fd[0],buf,sizeof(buf)-1);
if(result<=0)
break;
buf[result]='\0';//添加结束标志符
printf("子进程收到:%s\n",buf);
}
close(fd[0]);
}
else if(pid>0)//父进程
{
//父进程:写入信息通知父进程
close(fd[0]);//关闭读
//读
char buf[100]="";
while(1)
{
scanf("%s",buf);
write(fd[1],buf,strlen(buf));
}
close(fd[1]);
}
else
printf("创建失败\n");
return ;
}
三、有名管道(FIFO)
FIFO有时被称为命名管道。管道只能由相关进程使用,它们共同的祖先进程创建了管道。但是,通过FIFO,不相关的进程也能交换数据。有名管道也是一种半双工的通信方式,但是它允许无亲缘关系进程间的通信。
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
if (argc != 2) {
fprintf(stderr, "Argument error!\n");
exit(1);
}
if (mknod(argv[1], 0600|S_IFIFO, 0) < 0) {
perror("mknod()");
exit(1);
}
exit(0);
}