# 写在前面
[Linux系统编程 --管道](https://neo00.top/archives/linux%E7%B3%BB%E7%BB%9F%E7%BC%96%E7%A8%8B%E7%AE%A1%E9%81%93)主要介绍了匿名管道,本文主要介绍[FIFO有名管道](https://baike.baidu.com/item/FIFO%E7%AE%A1%E9%81%93/8466221?fr=aladdin)
# FIFO有名管道概述
无名管道,由于没有名字,只能用于亲缘关系的进程间通信。为了克服这个缺点,提出了命名管道(FIFO),也叫有名管道、FIFO 文件。
命名管道(FIFO)不同于无名管道之处在于它提供了一个路径名与之关联,以 `FIF`O 的文件形式存在于文件系统中,这样,即使与 FIFO 的创建进程不存在亲缘关系的进程,只要可以访问该路径,就能够彼此通过 `FIFO` 相互通信,因此,通过 `FIFO` 不相关的进程也能交换数据。
<font color="#FF0000">`FIFO` 是 `Linux` 基础文件类型中的一种。但 `FIFO` 文件在磁盘上没有数据块,仅仅用来标识一条通道。</font> 各进程可以打开这个文件进行 `read/write`,实际上是在读写内核通道,这样就实现了进程间通信。
<H4>命名管道(FIFO)和无名管道(pipe)有一些特点是相同的,不一样的地方在于</H4>
> 1. FIFO 在文件系统中作为一个特殊的文件存在而已, 但是 FIFO 的内用却存放在内存中
> 2. 当使用 FIFO 的进程退出后, FIFO 文件将继续保存在文件系统中以便以后使用
> 3. FIFO 有名字,不相关的进程可以通过打开命名管道进行进程间通信
## 命名管道的创建
### 通过函数创建
函数原型:int mkfifo(const char *pathname, mode_t mode);
作用:创建有名管道
头文件:
- #include <sys/types.h>
- #include <sys/stat.h>
参数:
- pathname: 普通的路径名,也就是创建后 FIFO 的名字。
- mode: 文件的权限,与打开普通文件的 open() 函数中的 mode 参数相同。
返回值:
- 成功:返回 0
- 失败:返回 -1
创建demo
```c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
int main(int argc, char *argv[]){
int ret;
ret = mkfifo("my_fifo", 0644); // 创建命名管道
if(ret != 0){ // 出错
perror("mkfifo");
}
return 0;
}
```
### 通过命令创建
`mkfifo + 管道名`
<font color="#FF0000">我是红色字体</font>
## 有名管道操作
后期的操作,把这个命名管道当做普通文件一样进行操作:`open()、write()、read()、close()`。但是,和无名管道一样,<font color="#FF0000">操作命名管道肯定要考虑默认情况下其阻塞特性</font> 。
下面验证的是默认情况下的特点,即 open() 的时候没有指定非阻塞标志( O_NONBLOCK )。测试如下:
- open() 以只读方式打开 FIFO 时,要阻塞到某个进程为写而打开此 FIFO
- open() 以只写方式打开 FIFO 时,要阻塞到某个进程为读而打开此 FIFO。
简单一句话,<font color="#FF0000">只读等着只写,只写等着只读,只有两个都执行到,才会往下执行</font>
```c
//写端
#include<stdio.h>
#include <unistd.h>
#include <error.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <sys/types.h>
#include <stdlib.h>
int main(int argc, char *argv[]){
int ret = mkfifo("myfifo",0644);
if(ret == 0){
perror("mkfifo error");
exit(1);
}
printf("before open\n");
int fd = open("myfifo", O_WRONLY);
if(fd < 0){
perror("open fifo");
exit(1);
}
printf("after open\n");
return 0;
}
```
```c
//读端
#include<stdio.h>
#include <unistd.h>
#include <error.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <sys/types.h>
#include <stdlib.h>
int main(int argc, char *argv[]){
int ret = mkfifo("myfifo",0644);
if(ret == 0){
perror("mkfifo error");
exit(1);
}
printf("before open\n");
int fd = open("myfifo", O_RDONLY);
if(fd < 0){
perror("open fifo");
exit(1);
}
printf("after open\n");
return 0;
}
```
上述代码证明,只有当读写都在执行时,程序才能执行。
<font color="#0000FF">如果大家不想在 open() 的时候阻塞,我们可以以可读可写方式打开 FIFO 文件,这样 open() 函数就不会阻塞。</font>
<font color="#FF0000">假如 FIFO 里没有数据,调用 read() 函数从 FIFO 里读数据时 read() 也会阻塞。这个特点和无名管道是一样的</font>
```c
//写端
#include<stdio.h>
#include <unistd.h>
#include <error.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <sys/types.h>
#include <stdlib.h>
int main(int argc, char *argv[]){
int ret = mkfifo("myfifo",0644);
if(ret == 0){
perror("mkfifo error");
exit(1);
}
printf("before open\n");
int fd = open("myfifo", O_WRONLY);
if(fd < 0){
perror("open fifo");
exit(1);
}
sleep(5); //让写端睡眠,看读端的状态
char *str = "hello fifo\n";;
write(fd, str, strlen(str));
return 0;
}
```
```c
// 写端
#include<stdio.h>
#include <unistd.h>
#include <error.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <sys/types.h>
#include <stdlib.h>
int main(int argc, char *argv[]){
int ret = mkfifo("myfifo",0644);
if(ret == 0){
perror("mkfifo error");
exit(1);
}
printf("before open\n");
int fd = open("myfifo", O_RDONLY);
if(fd < 0){
perror("open fifo");
exit(1);
}
char buf[1024];
int len;
len = read(fd, buf, sizeof(buf));
write(STDOUT_FILENO, buf, len);
return 0;
}
```
上述代码自行编译运行,才能明白其中奥妙
## 无聊的测试
pipe 能实现的 fifo 都可以,一对一,一对多,多对一,多对多,都可以,但是数据单向流通这个是前提
Linux系统编程 --管道(二)