命名管道
匿名管道没有名字,只能用于有亲缘关系的进程间通信,为了打破这一局限,Linux中设计了命名管道。命名管道又名FIFO(first in first out),它与匿名管道的不同之处在于:命名管道与系统中的一个路径名关联,以文件的形式存在于文件系统中,如此,系统中的不同进程可以通过FIFO的路径名访问FIFO文件,实现彼此间的通信。
虽然FIFO文件也是文件,但它非常特殊:FIFO文件严格遵循先进先出原则,当对其进行写操作时,数据会被添加到文件末尾;当对其进行读操作时,总是文件首部的数据先返回;FIFO对应的文件没有数据块,其本质与匿名管道相同,都是由内核管理的一块缓存,对该文件进行读写不会改变文件的大小;FIFO与管道一样,当缓冲区为空或缓冲区满时会产生阻塞。
Linux系统中可以通过mkfifo命令创建FIFO文件,该命令的命令格式如下:
mkfifo [选项] 参数
mkfifo命令的参数一般为文件名,其常用参数为-m,用于指定所创建文件的权限。假设要创建一个名为myfifo的FIFO文件,并将其权限设置为644,使用的命令如下:
$ mkfifo –m 644 myfifo
在程序中创建FIFO文件的函数与mkfifo同名,mkfifo()的头文件为sys/type.h与sys/stat.h,其函数声明如下:
int mkfifo(const char *pathname, mode_t mode);
mkfifo()调用成功时返回0;否则返回-1,并适当设置errno。mkfifo()的参数有两个,其中pathname为传入参数,表示管道文件的路径名;mode用于指定FIFO的权限。
下面通过案例来展示如何使用FIFO实现无关进程间的通信。
案例3:使用FIFO实现没有亲缘关系进程间的通信。由于是没有亲缘关系的进程间通信,因此需要在两段程序中实现,这里在程序fifo_write.c中实现FIFO的写操作,在程序fifo_read.c中实现FIFO的读操作。案例实现如下:
fifo_write.c //写
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <unistd.h>
5 #include <sys/types.h>
6 #include <sys/stat.h>
7 #include <fcntl.h>
8 int main(int argc,char *argv[])
9 {
10 if(argc<2) //判断是否传入文件名
11 {
12 printf("./a.out fifoname\n");
13 exit(1);
14 }
15 int ret = access(argv[1],F_OK); //判断fifo文件是否存在
16 if(ret==-1) //若fifo不存在就创建fifo
17 {
18 int r = mkfifo(argv[1],0664);
19 if(r==-1){ //判断文件是否创建成功
20 perror("mkfifo");
21 exit(1);
22 }
23 else{
24 printf("fifo creat success!\n");
25 }
26 }
27 int fd=open(argv[1],O_WRONLY); //以读写的方式打开文件
28 while(1){ //循环写入数据
29 char *p="hello,world!";
30 write(fd,p,strlen(p)+1);
31 sleep(1);
32 }
33 close(fd);
34 return 0;
35 }
fifo_read.c //读
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <unistd.h>
5 #include <sys/types.h>
6 #include <sys/stat.h>
7 #include <fcntl.h>
8 int main(int argc,char *argv[])
9 {
10 if(argc<2) //判断是否传入文件名
11 {
12 printf("./a.out fifoname\n");
13 exit(1);
14 }
15 int ret = access(argv[1],F_OK); //判断文件是否存在
16 if(ret==-1) //若文件不存在则创建文件
17 {
18 int r = mkfifo(argv[1],0664);
19 if(r==-1){
20 perror("mkfifo");
21 exit(1);
22 }
23 else{
24 printf("fifo creat success!\n");
25 }
26 }
27 int fd = open(argv[1],O_RDONLY); //打开文件
28 if(fd==-1){
29 perror("open");
30 exit(1);
31 }
32 while(1){ //不断读取fifo中的数据并打印
33 char buf[1024]={0};
34 read(fd,buf,sizeof(buf));
35 printf("buf=%s\n",buf);
36 }
37 close(fd); //关闭文件
38 return 0;
39 }
编译以上两段代码,设传入的文件名为myfifo,分别执行程序,执行read功能的程序所在终端中打印的信息如下:
buf=hello,world!
buf=hello,world!
buf=hello,world!
……
由于fifo_write.c中使用sleep(1),使进程每隔1秒向fifo中写入一条数据,因此read进程所在终端打印信息的时间间隔为1秒,当write进程写的速度较慢时,read进程会阻塞等待write进程写入数据;当write进程将fifo缓冲区写满时,write进程会阻塞等待read进程将数据读出。