Linux进程间通信第二讲 管道PIPE FIFO
目录二、管道(PIPE 、FIFO)2.1无名管道(PIPE)2.1.1 父子通信2.1.2 兄弟通信2.2有名管道(FIFO)二、管道(PIPE 、FIFO)最古老的IPC之一, 以管道文件作为媒介进行传输其中分为有名管道和无名管道无名管道的管道文件在文件系统中不可见, 而有名可见管道通信实质上是内存通信, 由内核负责2.1无名管道(PIPE)...
目录
二、管道(PIPE 、FIFO)
最古老的IPC之一, 以管道文件作为媒介进行传输
其中分为有名管道和无名管道
无名管道的管道文件在文件系统中不可见, 而有名可见
管道通信实质上是内存通信, 由内核负责
2.1无名管道(PIPE)
只能用于亲缘关系的进程(父子 、 兄弟), 由它的机制决定
无名管道的管道文件在文件系统中不可见
使用方法:
1、父进程调用pipe() 函数创建无名管道, 无名管道有读端 、 写端
2、用fork产生子进程, 子进程自动继承父进程的描述符 ,也就是 无名管道的 读端 、 写端
3、这是一种半双工通信, 一条管不能同时又进又出,想 读,就把写关了,另一边就把写关了,读就开 , 如下图所示
2.1.1 父子通信
首先父进程创建一个无名管道 , 有读、写描述符
然后fork 后产生一个子进程,它和父进程称为父子进程
这个子进程继承了父进程的读、写描述符
下面代码,子进程是写,所以要关掉读 ; 父进程是读,所以要关掉写
代码如下(pipe、父子进程):
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
//读、写 描述符
//pipefd[0] 读端描述符,从管道文件读
//pipefd[1] 写端描述符,往管道文件写
int pipefd[2];
//创建无名管道
int res = pipe(pipefd);
if(res==-1){
perror("pipe");
exit(-1);
}
//创建子进程
if(!fork()){//子
//写的时候,要关闭读端
close(pipefd[0]);
int i = 0;
for(i=0;i<50;i++){
write(pipefd[1],&i,sizeof(i));//往管道文件里写
//write 函数参数 介绍
//第一个参数:写描述符
//第二个参数:数据的地址
//第三个参数:数据的大小 (字节)
usleep(100000);
}
close(pipefd[1]); //退出之前,顺便关了写描述符
exit(0);
}
//父进程
printf("pid = %d\n",getpid());
char buf[10] = {};
int num = 0;//和子进程发送的数据类型保持一致
//读的时候,要关闭写端
close(pipefd[1]);
while(1){
res = read(pipefd[0],&num,sizeof(num));//从管道文件读
//read 函数参数 介绍
//第一个参数:读描述符
//第二个参数:数据的地址
//第三个参数:数据的大小 (字节)
if(res<=0)
break;
printf("%d\n",num);
}
close(pipefd[0]);//退出之前,顺便关了读描述符
wait(NULL);//等待子进程退出,回收它的资源(我的系统编程第二篇有讲过)
return 0;
}
2.1.2 兄弟通信
父进程创建了 读、写 描述符
fork 两次后产生了两个子进程(互为兄弟进程),它们都继承父进程的 读、写 描述符
在这里,父进程不参与通信,因此父进程的读、写描述符都需要关闭掉
下面的代码,子1是写,所以关掉读 ; 子2是读,所以关掉写
代码如下(pipe、兄弟进程):
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
int pipefd[2];
//创建无名管道
int res = pipe(pipefd);
if(res==-1){
perror("pipe");
exit(-1);
}
//创建子进程
if(!fork()){//子1
//写,关闭读端
close(pipefd[0]);
int i = 0;
for(i=0;i<50;i++){
write(pipefd[1],&i,sizeof(i));
usleep(100000);
}
close(pipefd[1]);
exit(0);
}
if(!fork()){//子2
char buf[10] = {};
int num = 0;
//读,关闭写端
close(pipefd[1]);
while(1){
res = read(pipefd[0],&num,sizeof(num));
if(res<=0)
break;
printf("%d\n",num);
}
close(pipefd[0]);
exit(0);
}
//父进程
printf("pid = %d\n",getpid());
//父进程不通信,关闭读端和写端
close(pipefd[0]);
close(pipefd[1]);
wait(NULL);
wait(NULL);
return 0;
}
2.2有名管道(FIFO)
用于所有进程的通信,不局限父子、兄弟进程
有名管道在文件系统中是可见,虽然可见, 但是是在内存当中
使用方法:
1、进程1创建一个有名管道文件,可以在文件系统中看到, 然后和它通信的进程2打开这个文件即可通信
2、没有读、写描述符, 这里只有文件描述符,用它进行读或写
3、这里也是一个半双工通信
例如进程1创建管道文件、然后打开文件获取文件描述符、接着进行用描述符来读管道文件
代码如下(fifo、读):
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
char buf[100] = {};
//1.创建管道文件
int res = mkfifo("/home/zzy/a.fifo",0666);
if(res==-1){
perror("mkfifo");
exit(-1);
}
//打开管道文件 读
int fd = open("/home/zzy/a.fifo",O_RDONLY);
if(fd==-1){
perror("open");
exit(-1);
}
//读管道
while(1){
res = read(fd,buf,sizeof(buf));
if(res<=0)
break;
printf("buf = %s\n",buf);
}
close(fd);
return 0;
}
而进程2不需要创建管道文件, 打开进程1创建的并获取文件描述符、接着进行用描述符来写管道文件
代码如下(fifo、写):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
char buf[100] = {};
//打开管道文件 写
int fd = open("/home/zzy/a.fifo",O_WRONLY); //有名管道在文件系统中可见
if(fd==-1){
perror("open");
exit(-1);
}
//写管道
while(1){
printf("请输入:");
fgets(buf,sizeof(buf),stdin);
write(fd,buf,sizeof(buf));
}
close(fd);
return 0;
}
更多推荐
所有评论(0)