【Linux】进程间通信 -- 命名管道

前言

在管道的通信中,除了匿名管道,还有一个命名管道
匿名管道只支持具有“亲戚关系”的进程间通信,而命名管道就可以支持不同的,任意的进程通信。
那就下来就开始我们今天的学习。

在这里插入图片描述

一. 命名管道

匿名管道的两种使用方式:指令的 ' | ' 和pipe()函数
命名管道也有两种使用方式:指令的 ' mkfifo 和 mkfile()函数'

我们使用一下指令的mkfile
mkfilo 命名管道名
在这里插入图片描述
管道文件属性的最前面的是p,普通文件是 -,链接文件是l

我们简单使用一下命名管道
在这里插入图片描述
这两个是不同的进程,一个是echo "hello" 将" hello "输出到显示器,但是重定向到 fifo管道中
一个是将fifo管道内容读出,重定向到cat,cat内部再将内容重定向到显示器
这样就实现两个不同进程通信了。

我们还可以更直观的感受,两个不同进程的通信。
在输入处,改成循环,这样写数据的进程就可以一直输入读数据的进程就一直读取。
在这里插入图片描述

命名管道,也是内存级文件,并不会像普通文件那样刷盘,将数据写入磁盘,同匿名管道一般,其内部就是一个缓冲区

二. 命名管道的应用

上面我们使用了指令层面的命名管道,接下来我们要使用代码创建命名管道,并且基于命名管道,实现多进程通信。

创建管道文件的函数
在这里插入图片描述

扫描二维码关注公众号,回复: 15052312 查看本文章

第一个参数是要创建的管道文件的文件名,第二个参数是管道文件的默认权限
创建成功返回0不成功返回-1

我们创建一个客户端,一个服务端,客户端写数据,服务端读数据。
因为我们要实现不同进程的通信,所以需要两个可执行程序。我们还可以将一些公共的信息放在一个 .hpp文件中

comm.hpp

#include<iostream>
#include<string>

//管道名
const std::string filename="./fifo";
//默认权限
const mode_t mode=0666;

我们让server客户端创建管道
server.cpp

#include<iostream>
#include<sys/types.h>
#include<sys/stat.h>
#include<cstring>
#include<cerrno>
#include<fcntl.h>
#include<unistd.h>
#include"comm.hpp"

//服务端
//接收数据
int main()
{
    
    
    //1. 创建管道文件,只需要创建一次

    //更改掩码
    umask(0);//该掩码的改变只印象该进程

    int n=mkfifo(filename.c_str(),mode);
    if(n!=0)
    {
    
    
        std::cout<<errno<<" : "<<strerror(errno)<<std::endl;
        return 1;
    }

    std::cout<<"create file success"<<std::endl;

    //2.服务端以读方式打开管道文件
    int rfd=open(filename.c_str(),O_RDONLY);
    if(rfd<0)
    {
    
    
        std::cout<<errno<<" : "<<strerror(errno)<<std::endl;
        return 2;
    }

    std::cout<<"open file success , begin ipc"<<std::endl;

    //3. 正常通信
    while(true)
    {
    
    
        char buffer[64]={
    
    0};
        ssize_t n=read(rfd,buffer,sizeof(buffer)-1);
        if(n>0)
        {
    
    
            buffer[n]='\0';
            std::cout<<"client# "<<buffer<<std::endl;
        }
        else if(n==0)
        {
    
    
            //写端关闭,返回值会变成0
            std::cout<<"通信结束"<<std::endl;
            break;
        }
        else
        {
    
    
            std::cout<<errno<<" : "<<strerror(errno)<<std::endl;
        }
    }

    close(rfd);

    //删除管道文件
    unlink(filename.c_str());
    return 0;
}

client.cpp

#include<iostream>
#include"comm.hpp"
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<cstring>
#include<cassert>

int main()
{
    
    
    //1.不需要创建管道,直接以写的方式打开就好
    int wfd=open(filename.c_str(),O_WRONLY);
    if(wfd<0)
    {
    
    
        std::cerr<<errno<<" : "<<strerror(errno)<<std::endl;
        return 1;
    }


    //开始进行常规通信
    char buffer[64];
    while(true)
    {
    
    
        std::cout<<"请输入你的消息:";
        //C语言的函数,关于字符串的输出输入不需要-1
        //系统调用的函数,关于字符串的函数需要-1
        char*msg=fgets(buffer,sizeof(buffer)-1,stdin);
        assert(msg);
        (void)msg;

        //将\n覆盖掉
        //abcdef\n\0   
        //01234567
        buffer[strlen(buffer)-1]='\0';

        //识别退出信息
        //忽略大小写的比较
        if(strcasecmp(buffer,"quit")==0)
        {
    
    
        	//输入"quit",就跳出循环
            break;
        }

        ssize_t n=write(wfd,buffer,strlen(buffer));
        assert(n>=0);
        (void)n;
    }

    close(wfd);

    return 0;
}

部分运行结果如下
在这里插入图片描述

结束语

本篇文章内容到此结束,感谢你的阅读

如果觉得本篇文章对你有所帮助的话,不妨点个赞支持一下博主,拜托啦,这对我真的很重要。
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/m0_72563041/article/details/130167626