Linux进程间通信——管道(下)

前文

一,什么是命名管道?

 二,命名管道的基本原理

三,创建命名管道实现两个进程对写

 四,匿名管道和命名管道的区别

总结


前文

上篇文章我们主要讲了匿名管道的定义以及基本原理,但是匿名管道有一个致命的缺陷,就是只能用于具有亲缘关系(有同一个祖先)的进程间的通信,而本文就是讲一下可以用于任意进程间通信的管道——命名管道

一,什么是命名管道?

命名管道其实就是一个特殊的文件,称为命名管道是因为在创建时需要加上名字,其中的内容是内存级别的专门用来进程间通信的,也就是说并不会保存到磁盘上面。

在linux中用下面的指令可以创建一个命名管道:

  • mkfifo [管道名字]

 

如上图所示,左右两边是同一台机器同一个路径下,我们首先在左边创建了匿名管道,然后我们就成功创造出fifo的特殊文件,然后我们用echo将内容重定向到命名管道中,然后左边cat进行读取,成功读取,echo和cat两个进程成功通信

 当然除了linux下指令的创建,在语言层操作系统也给我们提供了创建命名管道的接口,如下所示:

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

 1.创建成功返回0,失败返回其他

2.path为所创建的目录以及管道的名字,如./fifo

3.mode为命名管道的初始权限

其具体用法如下:

int main(int argc, char *argv[])
{
 mkfifo("./fifo", 0644);
 return 0;
}

 二,命名管道的基本原理

接下来我们讲一下命名管道的基本原理

 

 如上图,进程1以写的方式打开命名管道fifo,然后进程2以读的方式打开命名管道fifo,经过os的优化,进程2会直接用已经被进程1打开的fifo,这样进程1和进程2就看到了同一个文件,就可以通过这个文件进行通信,然后进程1写入内容,进程2进行读取,这样两个进程就通过命名管道fifo实现了通信

三,创建命名管道实现两个进程对写

写端

#include <iostream>
#include <cerrno>
#include <cstring>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string>
#include <assert.h>

using namespace std;

int main()
{
    //写方创造管道文件

    int n=mkfifo("./fifo",0666);
    if(n!=0)//创建失败
    {
        cout<<errno<<":"<<strerror(errno)<<endl;
        return 1;
    }

    //以写的方式打开文件
    int fd=open("./fifo",O_WRONLY);
    assert(fd>=0);

    //写入内容
    while(true)
    {
        char buffer[1024];

        char* ret=fgets(buffer,sizeof(buffer)-1,stdin);//从屏幕读取内容

        //写入管道
        size_t size=write(fd,buffer,strlen(buffer));
        assert(size>=0);//判断是否成功写入

    }

    //关闭文件
    close(fd);
    return 0;
}

读端

#include <iostream>
#include <cerrno>
#include <cstring>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <assert.h>
using namespace std;

int main()
{
    //直接以读的方式打开
    int fd=open("./fifo",O_RDONLY);
    assert(fd>=0);

    //读取内容
    while(true)
    {
        char buffer[1024];

        size_t size=read(fd,buffer,sizeof(buffer)-1);
        if(size>0)//读取有内容,打印内容
        {
            cout<<buffer<<endl;
        }
        else if(size=0)//读取数为0,说明写端不再写入,读端退出
        {
            cout<<"写端停止写入,读端退出"<<endl;
            break;
        }
        else//读取异常退出
        {
            cout<<"读取异常"<<endl;
            break;
        }
    }

    //关闭
    close(fd);
    return 0;
}

 运行效果

 四,匿名管道和命名管道的区别

1. 匿名管道由pipe函数创建并打开。
2. 命名管道由mkfifo函数创建,打开用open
3. FIFO(命名管道)与pipe(匿名管道)之间唯一的区别在它们创建与打开的方式不同,一但这些工作完成之后,它们具有相同的语义。

总结

本节命名管道讲完,管道的内容基本就结束了,如果兄弟们觉得有所收货可以给个三连鼓励一下

猜你喜欢

转载自blog.csdn.net/zcxmjw/article/details/131443749