前言
在管道的通信中,除了
匿名管道
,还有一个命名管道
。
匿名管道只支持具有“亲戚关系”
的进程间通信,而命名管道就可以支持不同的,任意的进程通信。
那就下来就开始我们今天的学习。
一. 命名管道
匿名管道的两种使用方式:
指令的 ' | ' 和pipe()函数
命名管道也有两种使用方式:指令的 ' mkfifo 和 mkfifo()函数'
我们使用一下指令的mkfifomkfilo 命名管道名
管道文件属性的最前面的是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)
{
//写端关闭,返回值会变成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;
}
部分运行结果如下
结束语
本篇文章内容到此结束,感谢你的阅读文章来源:https://www.toymoban.com/news/detail-418813.html
如果觉得本篇文章对你有所帮助的话,不妨点个赞支持一下博主,拜托啦,这对我真的很重要。
文章来源地址https://www.toymoban.com/news/detail-418813.html
到了这里,关于【Linux】进程间通信 -- 命名管道的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!