学科分类
目录
Linux编程

命名管道

匿名管道没有名字,只能用于有亲缘关系的进程间通信,为了打破这一局限,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进程将数据读出。

点击此处
隐藏目录