前面学习过(匿名)管道(见前面博客),匿名管道只能用于有亲缘关系的各个进程之间,为了解决这个限制,UNIX系统进而引入了FIFO,也称为有名管道(named pipe)。
FIFO(first in, first out),是一个半双工数据流,也即一个半双工管道。不同于匿名管道的是,每个FIFO有一个路径名(或文件名)与之关联,也即FIFO的名字。有了名字,无亲缘关系的进程间就可以通过管道进行数据传输了。
创建FIFO的方式:
- 使用shell命令 mkfifo创建一个有名管道
- 使用C库函数mkfifo创建一个有名管道
使用shell命令 mkfifo创建一个有名管道
1 |
[infor@s123 FIFO]$ mkfifo npipe
|
2 |
[infor@s123 FIFO]$ ls -l
|
3 |
prw-r--r-- 1 infor app 0 Nov 13 11:32 npipe |
我们在开启两个终端,分别为A和B。在A终端下将数据写入管道,在B终端下将数据读出来。
1 |
[infor@s123 FIFO]$ ping 10.4.123.124 >> npipe
|
2 |
#会阻塞在这里,等待另一个进程读 |
在终端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
|
使用C库函数mkfifo创建一个有名管道
1 |
#include <sys/types.h> |
2 |
#include <sys/stat.h> |
3 |
/* |
4 |
函数说明:依参数pathname建立特殊的FIFO文件,该文件必须不存在,而参数mode为该文件的权限 |
5 |
返回值:若成功则返回0,否则返回-1,错误原因存于errno中 |
6 |
*/ |
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将该结果读出。
01 |
#include <stdio.h> |
02 |
#include <stdlib.h> |
03 |
#include <sys/types.h> |
04 |
#include <sys/stat.h> |
05 |
#include <unistd.h> |
06 |
#include <fcntl.h> |
07 |
#include <errno.h> |
08 |
09 |
#define FIFO_NAME ("/tmp/fifo.1") // 设定FIFO的名字 |
10 |
#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) // 设定创建FIFO的权限 |
11 |
12 |
/*创建一个FIFO,等待另一个进程读取*/ |
13 |
int main()
|
14 |
{ |
15 |
int writefd;
|
16 |
char status[] = "success" ;
|
17 |
size_t n = 0;
|
18 |
19 |
// 创建FIFO
|
20 |
if (mkfifo(FIFO_NAME, FILE_MODE) < 0)
|
21 |
{
|
22 |
if (EEXIST == errno )
|
23 |
{
|
24 |
printf ( "FIFO:%s已经存在,不能重新创建\r\n" , FIFO_NAME);
|
25 |
}
|
26 |
else
|
27 |
{
|
28 |
perror ( "创建FIFO错误" );
|
29 |
exit (1);
|
30 |
}
|
31 |
}
|
32 |
33 |
// 打开FIFO
|
34 |
writefd = open(FIFO_NAME, O_WRONLY, 0);
|
35 |
if (-1 == writefd)
|
36 |
{
|
37 |
perror ( "打开FIFO失败" );
|
38 |
unlink(FIFO_NAME);
|
39 |
exit (1);
|
40 |
}
|
41 |
42 |
// 写入执行状态
|
43 |
n = write(writefd, status, strlen (status));
|
44 |
if (n != strlen (status))
|
45 |
{
|
46 |
perror ( "写入FIFO失败" );
|
47 |
unlink(FIFO_NAME);
|
48 |
exit (1);
|
49 |
}
|
50 |
51 |
if (-1 == close(writefd))
|
52 |
{
|
53 |
perror ( "关闭FIFO失败" );
|
54 |
unlink(FIFO_NAME);
|
55 |
exit (1);
|
56 |
}
|
57 |
58 |
return 0;
|
59 |
} |
1 |
[infor@s123 FIFO]$ gcc -o wnpipe wnpipe.c |
2 |
[infor@s123 FIFO]$ ./wnpipe |
3 |
#阻塞在这里等待另外一个进程读取FIFO |
这里我们看一下/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文件已经生成。
01 |
#include <stdio.h> |
02 |
#include <stdlib.h> |
03 |
#include <sys/types.h> |
04 |
#include <sys/stat.h> |
05 |
#include <unistd.h> |
06 |
#include <fcntl.h> |
07 |
#include <errno.h> |
08 |
09 |
#define FIFO_NAME ("/tmp/fifo.1") // 设定FIFO的名字 |
10 |
#define MAXLINE (1024) |
11 |
12 |
/*读取FIFO内容*/ |
13 |
int main()
|
14 |
{ |
15 |
int readfd;
|
16 |
char status[MAXLINE];
|
17 |
size_t n = 0;
|
18 |
19 |
// 打开FIFO
|
20 |
readfd = open(FIFO_NAME, O_RDONLY, 0);
|
21 |
if (-1 == readfd)
|
22 |
{
|
23 |
perror ( "打开FIFO失败" );
|
24 |
unlink(FIFO_NAME);
|
25 |
exit (1);
|
26 |
}
|
27 |
28 |
// 读取FIFO
|
29 |
n = read(readfd, status, MAXLINE);
|
30 |
if (-1 == n)
|
31 |
{
|
32 |
perror ( "读取FIFO失败" );
|
33 |
exit (1);
|
34 |
}
|
35 |
36 |
printf ( "管道内容:%s\r\n" , status);
|
37 |
38 |
// 关闭FIFO
|
39 |
if (-1 == close(readfd))
|
40 |
{
|
41 |
perror ( "关闭FIFO失败" );
|
42 |
unlink(FIFO_NAME);
|
43 |
exit (1);
|
44 |
}
|
45 |
46 |
// 删除FIFO
|
47 |
unlink(FIFO_NAME);
|
48 |
49 |
return 0;
|
50 |
} |
编译并执行:
1 |
[infor@s123 FIFO]$ gcc -o rnpipe rnpipe.c |
2 |
[infor@s123 FIFO]$ ./rnpipe |
3 |
管道内容:success |
这里我们再看一下/tmp/fifo.1 是否还存在:
1 |
[infor@s123 tmp]$ ls -l /tmp/fifo.1
|
2 |
ls : /tmp/fifo.1: No such file or directory
|