Linux 进程间通信 有名管道(fifo)

时间:2022-09-17 15:12:24

有名管道特点

1)无名管道只能用于具有亲缘关系的进程之间,这就限制了无名管道的使用范围

2)有名管道可以使互不相关的两个进程互相通信。

3)有名管道可以通过路径名来指出,并且在文件系统中可见,但内容存放在内存中

4)进程通过文件IO来操作有名管道

5)有名管道遵循先进先出规则

6)不支持如lseek() 操作

 

注意
以O_WRONLY打开管道,读阻塞
以O_RDWR打开管道,当管道中没有数据,读阻塞
//当进程用open打开有名管道用只读方式打开的话,则返回的文件描述符就代表管道的读端

创建有名管道

  int mkfifo(const char *filename, mode_t  mode)

  参数:filename 有名管道文件名(包括路径);mode 权限(读写0666)

  成功返回 0 ,失败返回-1 并设置 errno 号 errno == EEXIST 时表示该有名管道已经存在

对有名管道的操作是通过文件IO 中的open read write 等操作的

 

例子:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>


int main(int argc, const char *argv[])
{
    char buf[50] = {0};
    if(mkfifo("./fifo",0777) != 0 ) //在当前路径下(运行程序所在的路径)创建有名管道,有名管道权限读写执行
    {
        if(errno == EEXIST) //当该有名管道存在时,提示下
        {
            printf("File exists\n");
        }
        else
        {
            perror("mkfifo fail ");
            exit(1);
        }
    }

    int fd;
    fd = open("./fifo",O_RDWR);//读写方式打开,使用文件IO 操作有名管道
    if(fd < 0)
    {
        perror("open fifo fail: ");
        exit(1);
    }
    write(fd,"1234567",7);
    read(fd,buf,7);
    printf("%s\n",buf);
    return 0;
}

测试:

Linux 进程间通信 有名管道(fifo)

 

 例子:通过有名管道让两个进程实现文件的复制

 Linux 进程间通信 有名管道(fifo)

(1)读取文件写入有名管道中

/* 功能:实现在终端上输入获取文件名,读取文件内容,写到有名管道fifo中
 * */
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
int main(int argc, const char *argv[])
{
    char buf[50] = {0};
    if(mkfifo("./fifo",0777) != 0 ) //创建有名管道
    {
        if(errno == EEXIST)
        {
            printf("File exists\n");
        }
        else
        {
            perror("mkfifo fail ");
            exit(1);
        }
    }
    int fd_fifo,fd_file;
    fd_fifo = open("./fifo",O_WRONLY);//只写方式打开,管道描述符
    if(fd_fifo < 0)
    {
        perror("open fifo fail: ");
        exit(1);
    }
    fd_file = open(argv[1],O_RDONLY);//只读方式打开,源文件进行复制到管道中
    if(fd_file < 0)
    {
        perror("open source fail ");
        exit(1);
    }

    //循环读取文件内容
    ssize_t size;
    while(1)
    {
        size = read(fd_file,buf,50); //文件中读取数据,返回读取到多少数据
        if(size <= 0)
        {
            break;
        }
        write(fd_fifo,buf,size);
    }
    close(fd_file);//关闭读的源文件
    close(fd_fifo);
    return 0;
}

(2)读取有名管道中的数据,写入文件中实现复制

/* 功能:实现在有名管道中读取数据,写到文件中
 * */
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
int main(int argc, const char *argv[])
{
    char buf[50] = {0};
    if(mkfifo("./fifo",0777) != 0 ) //创建有名管道
    {
        if(errno == EEXIST) //有名管道存在的情况
        {
            printf("File exists\n");
        }
        else
        {
            perror("mkfifo fail ");
            exit(1);
        }
    }
    
    int fd_fifo,fd_file;  //此处fd_r是指有名管道,在有名管道中读取数据,写到文件中

    fd_fifo = open("./fifo",O_RDONLY);//读方式打开
    if(fd_fifo < 0)
    {
        perror("open fifo fail: ");
        exit(1);
    }
    
    fd_file = open(argv[1],O_WRONLY|O_CREAT|O_TRUNC,0666);//把从有名管道中读取的数据,写到文件中,只读,没有创建,清空打开
    if(fd_file < 0)
    {
        perror("fd_w open fail ");
        exit(1);
    }
    //fifo 中循环读取数据,然后写到文件中
    ssize_t size;
    while(1)
    {
        size = read(fd_fifo,buf,50); //读有名管道内容,返回读取多少个数据
        if(size <= 0)
        {
            break;
        }
        write(fd_file,buf,size); //写入文件中
    }
    close(fd_fifo);
    close(fd_file);
    return 0;
}

测试:此时要打开两个终端让两个进程进行通信,一个执行写操作,一个执行都操作(有名管道中有数据才可以读,且管道数据内容存在内存中)

Linux 进程间通信 有名管道(fifo)