Linux进程间通信,IPC-FIFO管道

一、命名管道(FIFO)

FIFO也被称为命名管道,是一种文件类型。匿名管道(pipe)只能在具有亲缘关系间的进程使用。但是,通过FIFO,不相关的进程也能交换数据。

FIFO(First Input First Output)是一种传统的按序执行方法,对管道及FIFO读总是从起始位置返回数据,对它们的写则把数据添加到末尾

二、命名管道函数

2.1 mkfifo函数

/*
功能:创建一个FIFO管道文件,用于提供FIFO功能
参数: 
     pathname:文件名或路径名,用于在文件系统中创建一个专用文件
     mode:用于规定FIFO文件权限,与open函数中mode一致。一旦创建了FIFO文件,就可以用一般的文件I/O函数操作它

返回值:成功返回 0,失败返回 -1
*/
#include <sys/types.h>
#include <sys/stat.h>

int mkfifo(const char *pathname, mode_t mode);

实际上,当我们调用mkfifo创建一个FIFO命名管道的时候,内核会为这个FIFO(伪)文件创建一个缓存区,当我们对FIFO文件进行open,read,write等文件I/O操作的时候就相当于操作这个缓存区,以此来实现进程间通信。

2.2 open函数

/*
功能:打开或创建文件,在打开或创建文件时可以制定文件的属性及用户的权限等各种参数。
参数:
     pathname:文件名或路径名。文件为当前目录下文件,路径名则为绝对路径名(如:/usr/local/mysql)
     oflages:打开的文件权限
     mode:设置文件访问权限的初始值
返回值:成功返回指向文件的文件描述符,失败返回 -1
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);

注:第三个参数是在第二个参数中有O_CREAT时才用作用。若没有,则第三个参数可以忽略。

三、编程示例:

3.1 编程目的:使用FIFO管道,实现两个无亲缘关系进程间的数据通信

3.2 编程思路:FIFO管道是一种半双工的通信方式,在同一时刻只能有一种数据流向,为实现数据双向流通,我们可以创建两条管道。管道0:A进程为读端,B进程为写端;管道1:A进程为写端,B进程为读端。

3.3 代码展示:

创建管道部分代码:

        //创建两个进程,输入0或1分别对应管道读写权限
        if(argc != 2)
        {
                printf("error! please choice one FIFO_FILE\n");
                return 0;
        }

        mode=atoi(argv[1]);
        printf("mode:%d\n",mode);
        
        //在创建管道前先使用access函数确认函数是否存在
        if(access(FIFO_FILE0,F_OK) < 0)
        {
                printf("file not exist");
                mkfifo(FIFO_FILE0,0666);
        }

        if(access(FIFO_FILE1,F_OK) < 0)
        {
                printf("file not exist");
                mkfifo(FIFO_FILE1,0666);
        }
     
        // 进程0:作为管道FIFO_FILE0的读端,FIFO_FILE1的写端
        // 注:这里以只读模式打开命名管道FIFO_FILE0的读端,默认是阻塞模式;如果命名管道的写端不被打开则open()将会一直阻塞,所以另外一个进程必须首先以写模式打开该文件FIFO_FILE0,否则会出现死锁
        if(mode == 0)
        {
                if((read_fd=open(FIFO_FILE0,O_RDONLY)) < 0)
                {
                        printf("open FIFO_FILE0 failure:%s\n",strerror(errno));
                        return 0;
                }
                if((write_fd=open(FIFO_FILE1,O_WRONLY)) < 0)
                {
                        printf("open FIFO_FILE1 failure:%s\n",strerror(errno));
                        return 0;
                }
        }
       
        // 进程1:作为管道FIFO_FILE0的写端,FIFO_FILE1的读端
        // 注:这里以只写模式打开命名管道FIFO_FILE0的写端,默认是阻塞模式;如果命名管道的读端不被打开则open()将会一直阻塞,所以另外一个进程必须首先以读模式打开该文件FIFO_FILE0,否则会出现死锁
        if(mode == 1)
        {
                if((write_fd=open(FIFO_FILE0,O_WRONLY)) < 0)
                {
                        printf("open FIFO_FILE0 failure:%s\n",strerror(errno));
                        return 0;
                }
                if((read_fd=open(FIFO_FILE1,O_RDONLY)) < 0)
                {
                        printf("open FIFO_FILE1 failure:%s\n",strerror(errno));
                        return 0;
                }
        }

        //管道FIFO_FILE0:进程1写入数据,进程0读取数据;
        //管道FIFO_FILE1:进程0写入数据,进程1读取数据;

以上为命名管道FIFO创建部分代码,可使用open函数返回的read_fd、write_fd向管道缓存区读取或写入数据,这里就不给大家演示了。