前面学习过(匿名)管道(见前面博客),匿名管道只能用于有亲缘关系的各个进程之间,为了解决这个限制,UNIX系统进而引入了FIFO,也称为有名管道(named pipe)。
FIFO(first in, first out),是一个半双工数据流,也即一个半双工管道。不同于匿名管道的是,每个FIFO有一个路径名(或文件名)与之关联,也即FIFO的名字。有了名字,无亲缘关系的进程间就可以通过管道进行数据传输了。
创建FIFO的方式:
- 使用shell命令 mkfifo创建一个有名管道
- 使用C库函数mkfifo创建一个有名管道
使用shell命令 mkfifo创建一个有名管道
1 | [infor@s123 FIFO]$ mkfifo npipe |
3 | prw-r--r-- 1 infor app 0 Nov 13 11:32 npipe |
上面我们创建了一个有名管道npipe,我们可以看到有名管道其实是一个文件,文件类型是“p”,管道类型。
我们在开启两个终端,分别为A和B。在A终端下将数据写入管道,在B终端下将数据读出来。
1 | [infor@s123 FIFO]$ ping 10.4.123.124 >> npipe |
在终端A下将ping的结果写入管道npipe,这里会一直阻塞到另一个进程将数据全部读出或中止读出。
1 | [infor@s123 FIFO]$ cat npipe |
2 | PING 10.4.123.124 (10.4.123.124) 56(84) bytes of data. |
3 | 64 bytes from 10.4.123.124: icmp_seq=0 ttl=128 time =0.838 ms |
4 | 64 bytes from 10.4.123.124: icmp_seq=1 ttl=128 time =0.835 ms |
5 | 64 bytes from 10.4.123.124: icmp_seq=2 ttl=128 time =0.843 ms |
6 | 64 bytes from 10.4.123.124: icmp_seq=3 ttl=128 time =0.834 ms |
在终端B下读取npipe。
使用C库函数mkfifo创建一个有名管道
7 | int
mkfifo( const
char *pathname, mode_t mode); |
对于创建方式,mkfifo隐含指定O_CREAT|O_EXCL,也即mkfifo创建一个新的FIFO,如果该FIFO已经存在,则会返回EEXIST错误。
对于参数mode可有如下选项:
S_IRUSR:当前用户可读
S_IWUSR:当前用户可写
S_IRGRP:组成员可读
S_IWGRP:组成员可写
S_IROTH:其他用户可读
S_IWOTH:其他用户可写
下面通过例子看下如何使用。
假如有这样一个案例。进程A执行完将执行结果写入管道,等待进程B将该结果读出。
09 | #define FIFO_NAME ("/tmp/fifo.1") // 设定FIFO的名字 |
10 | #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) // 设定创建FIFO的权限 |
16 | char status[] =
"success" ; |
20 | if (mkfifo(FIFO_NAME, FILE_MODE) < 0) |
24 | printf ( "FIFO:%s已经存在,不能重新创建\r\n" , FIFO_NAME); |
34 | writefd = open(FIFO_NAME, O_WRONLY, 0); |
43 | n = write(writefd, status, strlen (status)); |
44 | if (n != strlen (status)) |
51 | if (-1 == close(writefd)) |
编译并执行:
1 | [infor@s123 FIFO]$ gcc -o wnpipe wnpipe.c |
2 | [infor@s123 FIFO]$ ./wnpipe |
这里我们看一下/tmp/fifo.1 是否生成:
1 | [infor@s123 tmp]$ ls -l /tmp/fifo.1 |
2 | prw-r--r-- 1 infor app 0 Nov 13 12:58 /tmp/fifo.1 |
我们看到FIFO文件已经生成。
09 | #define FIFO_NAME ("/tmp/fifo.1") // 设定FIFO的名字 |
20 | readfd = open(FIFO_NAME, O_RDONLY, 0); |
29 | n = read(readfd, status, MAXLINE); |
36 | printf ( "管道内容:%s\r\n" , status); |
39 | if (-1 == close(readfd)) |
编译并执行:
1 | [infor@s123 FIFO]$ gcc -o rnpipe rnpipe.c |
2 | [infor@s123 FIFO]$ ./rnpipe |
这里我们再看一下/tmp/fifo.1 是否还存在:
1 | [infor@s123 tmp]$ ls -l /tmp/fifo.1 |
2 | ls : /tmp/fifo.1: No such file
or directory |