有名管道(FIFO)
-
相关概念
-
匿名管道由于没有名字,只能用于亲缘关系的进程间通信。为了克服这个缺点,提出了有名管道(FIFO),也叫命名管道,FIFO文件。
-
有名管道(FIFO)不同于匿名管道之处在于它提供了一个路径名与之相关联,以FIFO的文件形式存在于文件系统中,并且打开方式与打开一个普通文件是一样的,这样即使与FIFO的创建进程不存在亲缘关系的进程,只要访问该路径,就能彼此通过FIFO互相通信,因此,通过FIFO不相关的进程也能交换数据。
-
一旦打开了FIFO,就能在它上面使用与操作匿名管道和其他文件的系统调用一样的I/O系统调用了。与管道一样,FIFO也有一个读端和写端,并且从管道中读取数据的顺序与写入的顺序是一样的。
-
有名管道和匿名管道的区别:
-
FIFO在文件系统中作为一个特殊文件存在,但FIFO中的内容却存放在内存中。
-
当使用FIFO的进程退出后,FIFO文件将继续保存在文件系统中以便以后使用。
-
FIFO有名字,不相关的进程可以通过打开有名管道进行通信。
-
-
-
有名管道的使用
-
通过命令创建有名管道
mkfifo 名字
-
通过函数创建有名管道
#include<sys/types.h> #include<sys/stat.h> int mkfifo(const char *pathname,mode_t mode);
-
参数:
-pathname:管道名称的路径
-mode:文件的权限(和open函数的mode是一样的),是一个八进制的数
-
返回值:成功返回0;失败返回-1,并设置errno
使用mkfifo创建一个FIFO,就可以使用open打开它,常见的文件I/O函数都可用于FIFO。
FIFO严格遵守先进先出,对管道及FIFO的读总是从开始处返回数据,对他们的写则是把数据添加到末尾。它们不支持lseek()等文件定位操作。
-
-
注意事项
-
一个为只读而打开一个管道的进程会阻塞,直到另外一个进程为只写打开管道
-
一个为只写而打开一个管道的进程会阻塞,直到另外一个进程为只读打开管道
-
-
利用有名管道实现进程间通信(一个进程读数据,另一个进程写数据):
read.c:读数据
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
//从管道中读数据
int main(){
//打开管道文件
int fd=open("test",O_RDONLY);
if(fd==-1){
perror("open");
exit(0);
}
//读数据
while(1){
char buf[1024]={0};
int len=read(fd,buf,sizeof(buf));
if(len==0);{
printf("写端断开了连接...\n");
exit(0);
}
printf("recv buf: %s\n",buf);
}
return 0;
}
write.c:写数据
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<string.h>
//想管道中写数据
int main(){
//判断文件是否存在
int ret=access("test",F_OK);
if(ret==-1){
printf("管道不存在,创建管道\n");
//创建管道
ret=mkfifo("test",0664);
if(ret==-1){
perror("mkfifo");
exit(0);
}
}
//以只写的方式打开管道
int fd=open("test",O_WRONLY);
if(fd==-1){
perror("open");
exit(0);
}
//写数据
for(int i=0;i<100;++i){
char buf[1024];
sprintf(buf,"hello,%d\n",i);
printf("write data : %s\n",buf);
write(fd,buf,strlen(buf));
sleep(1);
}
close(fd);
return 0;
}
利用有名管道实现聊天功能:
chatA.c
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<stdlib.h>
#include<fcntl.h>
#include<string.h>
int main(){
//1.判断有名管道是否存在
int ret=access("fifo1",F_OK);
if(ret==-1){
//文件不存在
printf("管道不存在,创建对应的有名管道\n");
ret=mkfifo("fifo1",0664);
if(ret==-1){
perror("mkfifo");
exit(0);
}
}
ret=access("fifo2",F_OK);
if(ret==-1){
//文件不存在
printf("管道不存在,创建对应的有名管道\n");
ret=mkfifo("fifo2",0664);
if(ret==-1){
perror("mkfifo");
exit(0);
}
}
//2.以只写的方式打开管道1
int fdw=open("fifo1",O_WRONLY);
if(fdw==-1){
perror("open");
exit(0);
}
printf("打开管道fifo1成功,等待写入数据...\n");
//3.以只读的方式打开管道2
int fdr=open("fifo2",O_RDONLY);
if(fdr==-1){
perror("open");
exit(0);
}
printf("打开管道fifo2成功,等待读取...\n");
//4.循环的写、读数据
char buf[128];
pid_t pid=fork();
if(pid>0){
while(1){
//清空数据
memset(buf,0,128);
//获取标准输入的数据
fgets(buf,128,stdin);
//写数据
ret=write(fdw,buf,strlen(buf));
if(ret==-1){
perror("write");
exit(0);
}
}
}else if(pid==0){
while(1){
//读数据
memset(buf,0,128);
ret=read(fdr,buf,128);
if(ret==-1){
perror("read");
exit(0);
}
printf("buf:%s\n",buf);
}
}
//5.关闭文件描述符
close(fdw);
close(fdr);
return 0;
}
chatB.c
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<stdlib.h>
#include<fcntl.h>
#include<string.h>
int main(){
//1.判断有名管道是否存在
int ret=access("fifo1",F_OK);
if(ret==-1){
//文件不存在
printf("管道不存在,创建对应的有名管道\n");
ret=mkfifo("fifo1",0664);
if(ret==-1){
perror("mkfifo");
exit(0);
}
}
ret=access("fifo2",F_OK);
if(ret==-1){
//文件不存在
printf("管道不存在,创建对应的有名管道\n");
ret=mkfifo("fifo2",0664);
if(ret==-1){
perror("mkfifo");
exit(0);
}
}
//2.以只读的方式打开管道1
int fdr=open("fifo1",O_RDONLY);
if(fdr==-1){
perror("open");
exit(0);
}
printf("打开管道fifo1成功,等待读取...\n");
//3.以只写的方式打开管道2
int fdw=open("fifo2",O_WRONLY);
if(fdw==-1){
perror("open");
exit(0);
}
printf("打开管道fifo2成功,等待写入数据...\n");
//4.循环的读、写数据
char buf[128];
pid_t pid=fork();
if(pid>0){
while(1){
//读数据
memset(buf,0,128);
ret=read(fdr,buf,128);
if(ret==-1){
perror("read");
exit(0);
}
printf("buf:%s\n",buf);
}
}else if(pid==0){
while(1){
//清空数据
memset(buf,0,128);
//获取标准输入的数据
fgets(buf,128,stdin);
//写数据
ret=write(fdw,buf,strlen(buf));
if(ret==-1){
perror("write");
exit(0);
}
}
}
//5.关闭文件描述符
close(fdw);
close(fdr);
return 0;
}