有名管道打破了无名管道的限制,进化出了一个实实在在的 FIFO 类型的文件。这意味着即使没有亲缘关系的进程也可以互相通信了。所以,只要不同的进程打开 FIFO 文件,往此文件读写数据,就可以达到通信的目的。
不过 FIFO 文件与我们最开始讲的本地文件通信还是有着本质的区别,它长着普通文件的脑袋,却有着无名管道的基因。
1. 创建 FIFO 类型文件
- 通过命令 mkfifo 创建
如:
- 通过函数 mkfifo(3) 创建
比如:
该函数返回 0 表示成功,-1 失败。
2. FIFO 文件的特性
2.1 查看文件属性
当使用 mkfifo 创建 hello 文件后,查看文件信息如下:
某些版本的系统在 hello 文件后面还会跟着个
|
符号,像这样 hello|
2.2 使用 cat 命令打印 hello 文件内容
接下来你的 cat 命令被阻塞住。
开启另一个终端,执行:
然后你会看到被阻塞的 cat 又继续执行完毕,在屏幕打印 “hello world”。如果你反过来执行上面两个命令,会发现先执行的那个总是被阻塞。
2.3 fifo 文件特性
根据前面两个实验,可以总结:
- 文件属性前面标注的文件类型是 p,代表管道
- 文件大小是 0
- fifo 文件需要有读写两端,否则在打开 fifo 文件时会阻塞
当然了,如果在 open 的时候,使用了非阻塞方式,肯定是不会阻塞的。特别地,如果以非阻塞写的方式 open,同时没有进程为该文件以读的方式打开,会导致 open 返回错误(-1),同时 errno 设置成 ENXIO.
ENXIO O_NONBLOCK | O_WRONLY is set, the named file is a FIFO and no process has the file open for reading. Or, the file is a device special file and no corresponding device exists.
3. 实例
下面有两个程序,分别是发送端 send 和接收端面 recv。程序 send 从标准输入接收字符,并发送到程序 recv,同时 recv 将接收到的字符打印到屏幕。
3.1 发送端
3.2 接收端
3.3 编译
3.4 运行
因为 recv 端还没打开 hello 文件,这时候 send 是阻塞状态的。
再开启另一个终端:
这时候 send 端和 recv 端都在终端显示has opend fifo
此时在 send 端输入数据,recv 打印。
图1 运行结果
4. 总结
- 掌握如果创建 fifo 文件
- 知道 fifo 文件的特性
练习:kill 发送端或者接收端任何一个进程,观察程序运行结果,并验证你的观点。