【Linux】进程间通信 -- 命名管道
前言
在管道的通信中,除了
匿名管道
,还有一个命名管道
。
匿名管道只支持具有“亲戚关系”
的进程间通信,而命名管道就可以支持不同的,任意的进程通信。
那就下来就开始我们今天的学习。
文章目录
- 前言
- 一. 命名管道
- 二. 命名管道的应用
- 结束语
一. 命名管道
匿名管道的两种使用方式:
指令的 ' | ' 和pipe()函数
命名管道也有两种使用方式:指令的 ' mkfifo 和 mkfile()函数'
我们使用一下指令的mkfile
mkfilo 命名管道名
管道文件属性的最前面的是p
,普通文件是 -
,链接文件是l
我们简单使用一下命名管道
这两个是不同的进程,一个是echo "hello" 将" hello "输出到显示器,但是重定向到 fifo管道中
一个是将fifo管道内容读出,重定向到cat,cat内部再将内容重定向到显示器
这样就实现两个不同进程通信了。
我们还可以更直观的感受,两个不同进程的通信。
在输入处,改成循环,这样写数据的进程就可以一直输入
,读数据的进程就一直读取。
命名管道,也是
内存级文件
,并不会像普通文件那样刷盘
,将数据写入磁盘,同匿名管道一般,其内部就是一个缓冲区
。
二. 命名管道的应用
上面我们使用了指令层面的命名管道,接下来我们要
使用代码创建命名管道
,并且基于命名管道,实现多进程通信。
创建管道文件的函数
第一个参数是要创建的
管道文件的文件名
,第二个参数是管道文件的默认权限
创建成功返回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){//写端关闭,返回值会变成0std::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//系统调用的函数,关于字符串的函数需要-1char*msg=fgets(buffer,sizeof(buffer)-1,stdin);assert(msg);(void)msg;//将\\n覆盖掉//abcdef\\n\\0 //01234567buffer[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;
}
部分运行结果如下
结束语
本篇文章内容到此结束,感谢你的阅读
如果觉得本篇文章对你有所帮助的话,不妨点个赞支持一下博主,拜托啦,这对我真的很重要。