FIFO
FIFO Concept
管道的一個不足之處是沒有名字,因此,只能用於具有親緣關係的進程間通信,在命名管道(named pipe或FIFO)提出後,該限制得到了克服。
- FIFO不同於管道之處在於它提供一個路徑名(pathname)與之關聯,以FIFO的文件形式存儲於文件系統中
- 命名管道是一個設備文件,因此,即使進程與創建FIFO的進程不存在親緣關係,只要可以訪問該路徑,就能夠通過FIFO相互通信
- FIFO(first input first output)總是按照先進先出的原則工作,第一個被寫入的數據將首先從管道中讀出
- 命名管道存儲於硬盤,使用前要先打開(open())
- 命名管道也被稱爲FIFO文件,它是一種特殊類型的文件,它在文件系統中以文件名的形式存在,但是它的行爲卻和之前所講的沒有名字的管道(匿名管道)類似。
FIFO Create
- 在Shell下交互的創建一個命名管道
- 在程序中使用系統函數創建命名管道
//頭文件
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
//函數原型:
int mknod(const char *pathname, mode_t mode, dev_t dev);
int mkfifo(const char *pathname, mode_t mode);//建議儘量使用這個函數
//兩個函數的pathname和mode參數含義相同
//pathname-->命名管道的全路徑名
//mode-->創建命名管道的模式,指定文件的讀取權限
//dev-->設備值,只在創建設備文件是纔會用到
//返回值:成功(0);失敗(-1)
FIFO Using Process
- 創建FIFO(FIFO Create)
打開FIFO(open())
O_RDWR(讀寫方式):不會導致阻塞
O_RDONLY(只讀方式):調用open()函數的進程將會被阻塞,直到有寫方打開管道
O_WRONLY(寫方式):也會阻塞,直到有讀方打開管道使用FIFO(與管道基本相同)
//FIFO write
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<string.h>
#include<unistd.h>
#define PATHNAME "/home/wgb/code/FIFO/FIFO/file.tmp"//注意路徑的設置
#define MAX_SIZE 100
int main()
{
int ret = mkfifo(PATHNAME,S_IFIFO|0666);//創建管道
if(ret<0)
{
printf("mkfifo error\n");
printf("error num:%d error info:%s\n",ret,strerror(ret));
return -1;
}
int fd = open(PATHNAME,O_WRONLY);//打開管道
if(fd<0)
{
printf("open error\n");
printf("error num:%d error info:%s\n",fd,strerror(fd));
return -2;
}
char buf[MAX_SIZE];
memset(buf,'\0',sizeof(buf));
while(1)
{
scanf("%s",buf);
int ret = write(fd,buf,strlen(buf)+1);//寫
if(ret<0)
{
printf("write error\n");
printf("error num:%d error info:%s\n",fd,strerror(fd));
break;
}
if(strncmp(buf,"exit",4)==0)//輸入exit退出
break;
}
close(fd);
return 0;
}
//FIFO read:
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<string.h>
#include<unistd.h>
#define PATHNAME "/home/wgb/code/FIFO/FIFO/file.tmp"
#define MAX_SIZE 100
int main()
{
int fd = open(PATHNAME,O_RDONLY);//打開管道
if(fd<0)
{
printf("open error\n");
printf("error num:%d error info:%s\n",fd,strerror(fd));
return -2;
}
char buf[MAX_SIZE];
memset(buf,'\0',sizeof(buf));
while(1)
{
int ret = read(fd,buf,sizeof(buf));//讀取
if(ret<0)
{
printf("open error\n");
printf("error num:%d error info:%s\n",fd,strerror(fd));
break;
}
printf("%s\n",buf);
if(strncmp(buf,"exit",4)==0)//退出
break;
}
close(fd);//打開就要關閉
return 0;
}
總結
文件系統中的路徑名是全局的,各進程都可以訪問,因此可以用文件系統中的路徑名來標識一個IPC通道。
由於Linux中所有的事物都可被視爲文文件,所以對命名管道的使用也就變得與文件操作非常的統一,也使它的使用非常方便,同時我們也可以像平常的文件名一樣在命令中使用。
mkfifo函數的作用用是在文文件系統中創建一一個文文件,該文文件用用於提供FIFO功能,即命名管道。
前邊講的那些管道都沒有名字,因此它們被稱爲匿名管道,或簡稱管道。對文件系統來說,匿名管道是不可見的,它的作用僅限於在父進程和子進程兩個進程間進行通信。而命名管道是一個可見的文件,因此,它可以用於任何兩個進程之間的通信,不管這兩個進程是不是父子進程,也不管這兩個進程之間有沒有關係。