命名管道FIFO

fork出来的进程通过普通管道pipe传递数据,而这些进程他们最先都是由一个主进程给构造出来的,也就是有相关性,而如果是想在完全不想关的进程之间传输数据,Linux下可以通过一种特殊的文件来完成,命名管道,它在文件系统中是以文件名的形式存在的

命令行创建命名管道:

[lihui@localhost ~]# mkfifo one
[lihui@localhost ~]# ll one
prw-r--r--. 1 lihui lihui 0 Jan 29 00:28 one
[root@localhost ~]# ls -lF one
prw-r--r--. 1 lihui lihui 0 Jan 29 00:28 one|
[lihui@localhost ~]# rm -rf one
[lihui@localhost ~]# ls one
ls: cannot access one: No such file or directory

可以看到第一个属性p,表示管道,同时最后面有一个“|”符号,所有脚本语言这个都表示管道符号

 

命名管道由于以文件名形式存在文件系统中,可以跟其它文件名一样来命令使用,下面的例子可以查看FIFO文件的行为

1:创建一个FIFO文件,显然他是空的

[lihui@localhost ~]# mkfifo one
[lihui@localhost ~]# ll one 
prw-r--r--. 1 lihui lihui 0 Jan 29 00:35 one

2:读这个空的FIFO文件,就会挂在这里

终端1:

[lihui@localhost ~]# cat < one 光标

3:开另一个终端,向这个FIFO文件当中写数据

终端2
[lihui@localhost ~]# echo "Hello World" > one
[lihui@localhost ~]# 

4:查看挂在那里等待数据的第一个终端的输出

终端1
[lihui@localhost ~]# cat < one 
Hello World
[lihui@localhost ~]# 

可以看到cat命令已经输出了结果,这里如果不向FIFO发送任何数据,cat会一直挂起,你可以ctrl+c来中断它

也可以直接将cat命令放到后来执行,一个终端完成:

[lihui@localhost ~]# cat < one &
[1] 32288
[lihui@localhost ~]# echo "Hello World" > one
[lihui@localhost ~]# Hello World
^C
[1]+  Done                    cat < one

这里cat一开始就在后台被阻塞了,当echo提供数据后,cat读取这些数据打印到标准输出上,cat就退出了,不再等待更多数据,没有阻塞是因为echo命令将数据放到了FIFO之后,管道将被关闭,所以cat程序中read调用返回了0字节,已经到达文件尾

如果想检验一下,或许你觉得打印了Hello World之后,还挂在那里,假如另一个终端echo一个字符串,会发现阻塞在那里了,就像没有进程读取数据导致发送端阻塞一样,可见cat此时的确是已经退出了

[lihui@localhost ~]# echo "Hello World" > one
^C-bash: one: Interrupted system call

 

命名管道的创建可以通过下面API接口创建

#include <sys/stat.h>
int mkfifo(const char *filename, mode_t mode);

返回0表示创建成功

#include <stdio.h>
#include <sys/stat.h>

int main(){
    if (mkfifo("one", 0777) == 0)
        printf("FIFO created !\n");
    else
        printf("FIFO created failed!\n");
    return 0;
}
[lihui@localhost ~]# ./a.out 
FIFO created !

发表回复