管道是一种最基本的IPC机制,作用于有血缘关系的进程之间,完成数据传递。调用pipe系统函数即可创建一个管道。有如下特质:
1. 其本质是一个伪文件(实为内核缓冲区)
2. 由两个文件描述符引用,一个表示读端,一个表示写端。
3. 规定数据从管道的写端流入管道,从读端流出。
管道的原理: 管道实为内核使用环形队列机制,借助内核缓冲区(4k)实现。
管道 分为 标准流管道,无名管道(PIPE),命名管道(FIFO)
① 数据自己读不能自己写。
② 数据一旦被读走,便不在管道中存在,不可反复读取。
③ 由于管道采用半双工通信方式。因此,数据只能在一个方向上流动。
其中 无名管道 ’标准管道 只能在有公共祖先的进程间使用管道。
demo 两个子进程 写父进程读
#include
#include
#include
#include
#include
int main(void)
{
pid_t pid;
int fd[2], i, n;
char buf[1024];
int ret = pipe(fd);
if (ret == -1)
{
perror("pipe error");
exit(1);
}
for (i = 0; i < 2; i++)
{
if ((pid = fork()) == 0)
{
if (i == 0)
{
close(fd[0]);
write(fd[1], "1.hello\n", strlen("1.hello\n"));
}
else if (i == 1)
{
close(fd[0]);
write(fd[1], "2.world\n", strlen("2.world\n"));
}
break;
}
else if (pid == -1)
{
perror("pipe error");
exit(1);
}
}
if (pid > 0)
{
close(fd[1]); //父进程关闭写端,留读端读取数据
// sleep(1);
n = read(fd[0], buf, 1024); //从管道中读数据
write(STDOUT_FILENO, buf, n);
for (i = 0; i < 2; i++) //两个儿子wait两次
wait(NULL);
}
return 0;
}
结果
#include
#include
#include
#include
#define BUFSIZE 1024
int main()
{
FILE *fp;
char *cmd = "printenv";
char buf[BUFSIZE];
buf[BUFSIZE-1] = '\0';
if((fp=popen(cmd,"r"))==NULL)
perror("popen");
while((fgets(buf,BUFSIZE,fp))!=NULL)
printf("%s",buf);
pclose(fp);
exit(0);
}
上述管道虽然实现了进程间通信,但是它具有一定的局限性:首先,这个管道只能是具有血缘关系的进程之间通信;第二,它只能实现一个进程写另一个进程读,而如果需要两者同时进行时,就得重新打开一个管道。
为了使任意两个进程之间能够通信,就提出了命名管道(named pipe 或 FIFO)
不支持seek 先进先出
原型
fifo_read.c
#include
#include
#include
#include
#include
int main()
{
int fd;
int len;
char buf[1024];
if(mkfifo("fifo1", 0666) < 0 && errno!=EEXIST) // 创建FIFO管道
perror("Create FIFO Failed");
if((fd = open("fifo1", O_RDONLY)) < 0) // 以读打开FIFO
{
perror("Open FIFO Failed");
exit(1);
}
while((len = read(fd, buf, 1024)) > 0) // 读取FIFO管道
printf("Read message: %s", buf);
close(fd); // 关闭FIFO文件
return 0;
}
fifo_read.c
#include
#include // exit
#include // O_WRONLY
#include
#include // time
int main()
{
int fd;
int n, i;
char buf[1024];
time_t tp;
printf("I am %d process.\n", getpid()); // 说明进程ID
if((fd = open("fifo1", O_WRONLY)) < 0) // 以写打开一个FIFO
{
perror("Open FIFO Failed");
exit(1);
}
for(i=0; i<10; ++i)
{
time(&tp); // 取系统当前时间
n=sprintf(buf,"Process %d's time is %s",getpid(),ctime(&tp));
printf("Send message: %s", buf); // 打印
if(write(fd, buf, n+1) < 0) // 写入到FIFO中
{
perror("Write FIFO Failed");
close(fd);
exit(1);
}
sleep(1); // 休眠1秒
}
close(fd); // 关闭FIFO文件
return 0;
}