【Linux】-进程间通信-命名管道文件(没有关系的进程间进行通信),以及写一个日志模板

在这里插入图片描述
💖作者:小树苗渴望变成参天大树🎈
🎉作者宣言:认真写好每一篇博客💤
🎊作者gitee:gitee✨
💞作者专栏:C语言,数据结构初阶,Linux,C++ 动态规划算法🎄
如 果 你 喜 欢 作 者 的 文 章 ,就 给 作 者 点 点 关 注 吧!

文章目录

  • 前言
  • 一、演示命名管道文件
  • 二、理解
  • 三,编写代码
  • 四、编写日志代码
    • 4.1代码
    • 4.2 介绍知识点
    • 4.3 看加入日志的效果
    • 五、总结


前言

今天博主开始给大家讲解一下命名管道文件,就是相比较于匿名管道,是有名字的,命名管道文件的特点进行没有任何关系的进程间进行通信,他的原理几乎和匿名管道差不多,但是还是有差距,博主在匿名管道哪里没讲开,因为需要两者对比的区分开才更有效果,他进行通信的时候和文件操作差不多,话不多说,开始进入正文讲解

讲解逻辑:

  1. 演示命名管道文件
  2. 理解命名管道文件
  3. 编码实现

一、演示命名管道文件

我们在命令行当中通过指令来实现两个进程之间的通信,因为指令也是程序,每个指令互相都是没有关系的,我们使用mkfifo这个指令来创建命名管道文件

mkfifo myfifo

在这里插入图片描述
在这里插入图片描述

通过上面的演示,我们echo往管道文件写入,但是他是阻塞的,等到有人来读取他,他才没有阻塞,所以我们得出来一个结论,我们管道文件只有在读写端都接入的时候,才会被打开。这也是管道文件的一个特性,符合同步互斥机制。

管道文件的演示很简单,接下来我们直接来谈谈他的理解

二、理解

大家应该很奇怪,为什么叫理解,不讲原理吗,原因是我们的命名管道和匿名管道原理差不多,但是周边有点小不同,需要大家去理解一下。

  1. 如果两个不同的进程打开同一个文件的时候,os会打开几个文件?答案是一个,文件系统只需要管理一份就好,相信细心的小伙伴发现了·,博主将匿名的,叫做匿名管道,将命名的,叫做命名管道文件,说明在本质上我们的匿名管道不是我们用户看到的文件一样,

在这里插入图片描述

可以简单理解命名管道文件在普通文件和匿名管道之间,但是效率还是匿名管道强一点,因为少了一层拷贝,我们可以通过下面的脚本来观察,管道文件确实是不刷盘的。
在这里插入图片描述
博主使用一直往管道问价那里面然后读取,我们使用 ls -l | grep myfifo 去查看,发现文件大小一直为0,所以内容不在硬盘上。

  1. 进程间通信的本质是,让不同的进程看到不同的资源,有了上面的理解1,这份资源也是os给的,而且管道文件也不在硬盘上,博主这是云服务器,当我们在后台开机重启的时候,这个管道文件应该也随之消失,他的生命周期是随着内核的,而不是随着进程的,通过上面的演示也可以看出来,我们的程序结束了,他依旧存在,还有大家别重新打开xshell,然后发现管道文件还在,难道博主说的不对,你重新打开xshell只是bash这个进程重新加载了,就好比你关闭电脑上的一个软件重新启动一样,大家别搞错了,我们的Linux系统是一直在运行的。
  2. 通过理解2,我们创建了管道文件,是为了让不同进程看到同一份资源,也就是看到这个管道文件,那你是怎么知道这两个进程打开的是同一个文件呢??答案是同路径下同文件名,路径天生是唯一的,根据文件系统的知识,我们同路径下的文件名也是唯一的,所以通过这两点–唯一性,让不同的进程打开的是同一个文件。至此我们建立了命名管道文件。

通过上面的理解,大家应该理解了命名管道文件,原理和匿名很相似,所以接下来博主直接带大家来编写大家,让大家更好的理解

三,编写代码

既然是命名管道文件,肯定不能像创建普通文件一样使用mkdir去创建,按照我们之前的经验,准确来说是进程间通信的本质,我们认为这个命名管道文件应该是由操作系统去创建,我们来看看怎么在代码中创建管道:
在这里插入图片描述

第一个参数是创建管道的路径和文件名,第二个参数文件

用完想删除管道文件,使用unlink函数
在这里插入图片描述

传刚才文件的路径和文件名就可以了

serverPipe.cc

#include "fifo.hpp"//此进程是服务端,给客户端发送内容的
int main()
{//创建管道文件int n=mkfifo(PATHNAME,MODE);if(n<0){perror("mkfifo:");exit(EXIT_MKFIFO);}//打开管道,等待读入方打开管道,这个才会打开int fd=open(PATHNAME,O_WRONLY);if(fd<0){perror("open:");exit(EXIT_OPEN);}//进行通信string s;while(true){cout << "Please Enter@ ";getline(cin, s);write(fd,s.c_str(),s.size());}//关闭管道close(fd);//删除管道文件int m=unlink(PATHNAME);if(m<0){perror("unlink:");exit(EXIT_UNLINK);}return 0;
}

clientPipe.cc

#include "fifo.hpp"//此进程是客户端,接收服务端发过来的消息
int main()
{//创建管道文件另一个进程已经帮助我们做好了,我们拿来使用就好了int fd=open(PATHNAME,O_RDONLY);if(fd<0){perror("open:");exit(EXIT_OPEN);}char buffer[N];while(true){buffer[0]=0;size_t n=read(fd,buffer,sizeof(buffer));if (n > 0){buffer[n] = 0;cout << "server say# " << buffer << endl;}else if (n == 0){printf("server quit, me too!, error string: %s, error code: %d\n", strerror(errno), errno);break;}elsebreak;}close(fd);return 0;
}

fifo.hpp

#pragma once#include<iostream>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<string>
#include<string.h>using namespace std;#define PATHNAME "./myfifo"  //创建管道文件的路径和文件名
#define MODE 0664  //权限
#define N 1024#define EXIT_MKFIFO -1
#define EXIT_OPEN -2
#define EXIT_UNLINK -3

在这里插入图片描述
这个理解起来不难,大家也看到效果了。读端会等待写端,所以也是具有同步互斥机制的

但是代码不够优雅,博主选择将创建管道和删除管道,放到一个类里面,都放在头文件里面:

fifo.hpp

#pragma once#include<iostream>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<string>
#include<string.h>using namespace std;#define PATHNAME "./myfifo"  //创建管道文件的路径和文件名
#define MODE 0664  //权限
#define N 1024#define EXIT_MKFIFO -1
#define EXIT_OPEN -2
#define EXIT_UNLINK -3class Init
{
public:Init(){int n=mkfifo(PATHNAME,MODE);if(n<0){perror("mkfifo:");exit(EXIT_MKFIFO);}}~Init(){int m=unlink(PATHNAME);if(m<0){perror("unlink:");exit(EXIT_UNLINK);}}
};

四、编写日志代码

我们发现每次写代码打印错误信息的时候,都是直接写的,而现在博主就交给你们一个办法,以后再学习中都可以使用到,而且这个以后去公司的时候,也不需要你自己去写的,我们了解这个原理就可以了,这里会介绍一些不常用的函数接口,接下来博主就来介绍一下什么是日志。

4.1代码

我们的日志是有等级之分的,先简单的来区分一下:

#define INFO 0  //常规消息
#define WARNING 1 //警告消息
#define ERROR 2 //错误消息
#define FATAL 3 //非常严重消息
#define DEBUG 4 //调试消息

日志一般都会有时间的,所以要重点介绍一下获取时间的函数,其次日志等级是认为规定,所以传参要传等级,我们打印的格式以及要打印多少个信息也是我们认为控制的,所以最好传可变参数,这样就可以很好的控制了。类似于这样:
log(INFO, "server open file done, error string: %s, error code: %d", strerror(errno), errno);

博主先把代码粘贴出来,再来解释博主认为你们不理解的地方

#include<iostream>
#include<string>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
using namespace std;//日志等级
#define INFO 0  //常规消息
#define WARNING 1 //警告消息
#define ERROR 2 //错误消息
#define FATAL 3 //非常严重消息
#define DEBUG 4 //调试消息//打印方式
#define SCREEN  0
#define ONEFILE 1
#define CLASSFILE 2#define SIZE 1024
#define LOGTXT "log.txt" //默认的存放所有日志信息的文件
class Log
{
public:Log(){printmethod=SCREEN;//默认的打印方式path="./log/";//默认的存放日志的路径}void enable(int method){printmethod=method;//自定义打印方式}string leveltostring(int level)//将日志等级信息转换成字符串,打印的时候要使用到{switch(level){case INFO:return "INFO:";case WARNING:return "WARNING:";case ERROR:return "ERROR:";case FATAL:return "FATAL:";case DEBUG:return "DEBUG:";default:return "NONE";}}void operator()(int level,const char* famat,...){time_t t=time(nullptr);//获得时间戳struct tm*ctime=localtime(&t);//这是获取当地的一个时间,这个结构体李米娜有许多属性。char leftbuffer[SIZE];//存放日志时间等信息snprintf(leftbuffer,sizeof(leftbuffer),"[%s][%d-%d-%d-%d:%d:%d]",leveltostring(level).c_str(),ctime->tm_year+1990,ctime->tm_mon+1,ctime->tm_mday,ctime->tm_hour,ctime->tm_min,ctime->tm_sec);va_list s;va_start(s,famat);char rightbuffer[SIZE];//存放日志等级信息,有用户去决定的vsnprintf(rightbuffer,sizeof(rightbuffer),famat,s);va_end(s);char logtxt[SIZE*2];//拼在一起snprintf(logtxt,sizeof(logtxt),"%s %s",leftbuffer,rightbuffer);printfmethod(level,logtxt);//打印方式}void printfmethod(int level,const string&logtxt){switch(printmethod){case SCREEN:cout<<logtxt<<endl;break;case ONEFILE:printfonefile(LOGTXT,logtxt);//本来一个参数就可以,但是为了适配下面函数的调用,加了一个参数break;case CLASSFILE:printfclassfile(level,logtxt);break;}}void printfonefile(const string& logname,const string&logtxt){string _logtxt=path+LOGTXT;int fd=open(_logtxt.c_str(),O_CREAT|O_WRONLY|O_APPEND);if(fd<0){perror("open:");return;}write(fd,logtxt.c_str(),logtxt.size());close(fd);}void printfclassfile(int level,const string&logtxt)//多文件打印{string _logtxt=LOGTXT;_logtxt+=".";_logtxt+=leveltostring(level);//为了区分不同的日志等职,分别放到不同的文件里面。printfonefile(_logtxt,logtxt);}~Log(){}
private:int printmethod;//打印方式string path;//使日志文件和可执行程序不在一个目录下,单独建立一个目录
};

4.2 介绍知识点

第一个:va_list是什么,这是类型,而va_start这其实是一个读取可变模板参数的起始位置的函数,我给大家据一个例子:任意数相加

int sum(int n,...)
{va_list s;va_start(s,n);int sum=0;while(n){sum+=va_arg(s,int);n--;}va_end(s);return sum;
}

在这里插入图片描述
在这里插入图片描述

所以我们对于这种可变参数在一开始都至少有一个形参。这样大家应该知道作用了吧,我们在写rightbuffer这个字符串的时候还需要一个函数vsnprintf
在这里插入图片描述
这样就很明显看出来这个函数的作用了。

第二个
我们来看获取时间的函数,最重要的localtime·
在这里插入图片描述

这样一看就很清楚了,只是陌生函数多了,但是理解起来和用法都很简单。

4.3 看加入日志的效果

  1. 往屏幕上打印:
    在这里插入图片描述

通过打印出来的日志我们也可以发现,我们的管道只有双方都打开才会打开。这样打出来的消息就很规范

  1. 往一个文件里面打印
    通过log.enable(ONEFILE);去修改打印方式
    在这里插入图片描述

  2. 往多个文件打印,分类

  3. 通过log.enable(CLASSFILE);去修改打印方式
    在这里插入图片描述

通过上面的演示,我们发现我们以后想要打印一些错误信息,就可以来复用这个模板了,让程序看上去非常的优雅。大家下去在好好的理解一下这个模板。

五、总结

今天讲解了命名管道,有了匿名管道的铺垫,我们在理解命名管道的时候就简单许多,所以操作来说也是很简单的,大家下去夺取理解就好了,我们今天讲的重点还有一个就是日志,这个让大家以后都可以重复使用的一个模板非常的方便,大家如果不想去实现,就使用博主写的吧,希望大家下去实现以下,这样更容易理解,而且更有印象。我们下篇讲解的是共享内存的知识,希望大家过啊里支持一下

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/150391.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Vue3.0和2.0语法不同分析

前言&#xff1a;本篇文章只做VUE3.0和VUE2.0语法上的不同分析&#xff0c;不做性能和源码架构等的分析。 一、VUE3.0和VUE2.0代码结构不同 VUE3.0代码实例 <template><div><span>count is {{ count }}</span><span>plusOne is {{ plusOne }}…

Games104现代游戏引擎笔记 面向数据编程与任务系统

Basics of Parallel Programming 并行编程的基础 核达到了上限&#xff0c;无法越做越快&#xff0c;只能通过更多的核来解决问题 Process 进程 有独立的存储单元&#xff0c;系统去管理&#xff0c;需要通过特殊机制去交换信息 Thread 线程 在进程之内&#xff0c;共享了内存…

Linux本地docker一键部署traefik+内网穿透工具实现远程访问Web UI管理界面

文章目录 前言1. Docker 部署 Trfɪk2. 本地访问traefik测试3. Linux 安装cpolar4. 配置Traefik公网访问地址5. 公网远程访问Traefik6. 固定Traefik公网地址 前言 Trfɪk 是一个云原生的新型的 HTTP 反向代理、负载均衡软件&#xff0c;能轻易的部署微服务。它支持多种后端 (D…

LabVIEW和NIUSRP硬件加快了认知无线电开发

LabVIEW和NIUSRP硬件加快了认知无线电开发 对于电视频谱&#xff0c;主用户传输有两种类型&#xff1a;广播电视和节目制作和特殊事件(PMSE)设备。广播塔的位置已知&#xff0c;且覆盖电视传输塔&#xff08;复用器&#xff09;附近的某个特定地理区域&#xff08;称为排除区域…

进程管理(四)

管程概念及实现要旨 管程引入了条件变量condition。 wait操作,把当前进程挂到条件变量对应的阻塞队列上去,signal把条件队列上的对手进程唤醒。 注意:条件变量的signal操作和信号量的signal是有区别的。条件变量的signal可能啥都不干,如果有阻塞的进程唤醒,没有啥事都不做…

从零开始的C++(十八)

avl树中insert的模拟实现 avl树特点&#xff1a; 1.是搜索二叉树 2.每个结点的左右子树高度差的绝对值不超过2 inser模拟实现&#xff1a; // 右单旋void RotateR(Node* pParent){Node* parent pParent;Node* pr parent->_pRight;Node* prl pr->_pLeft;//记录父节点…

红海营销时代,内容占位的出海品牌更有机会营销占位

#01 品牌出海&#xff1a;内容占位就是品牌营销占位 红海营销时代&#xff0c;内容信息充斥着用户周边。无论线上还是线下&#xff0c;生活工作、休闲娱乐等不同场景内&#xff0c;广告信息均无孔不入。对于用户来说&#xff0c;能记住的品牌或者商品往往寥寥无几。 占位营销…

全网好评!12个网络工程师必备工具!

你们好&#xff0c;我的网工朋友。 今天来一期久违的工具推荐。工欲善其事必先利其器&#xff0c;好的工具势必会让网工们如虎添翼。 快速掌握正确的工具&#xff0c;意味着你可以轻松地完成复杂的工作。 但市面上的软件太多了&#xff0c;到底选用哪个工具&#xff0c;这还…

【最新Tomcat】IntelliJ IDEA通用配置Tomcat教程(超详细)

前言 IntelliJ IDEA是一个强大的集成开发环境&#xff0c;能够大大简化Java应用程序的开发和部署过程。而Tomcat作为一个流行的Java Web服务器&#xff0c;其与IntelliJ IDEA的整合能够提供便捷的开发环境&#xff0c;让开发人员更专注于代码的创作与优化。 在配置IntelliJ IDE…

linux在非联网、无网络环境下,使用yumdownload、reportrack方法安装rpm包

文章目录 前言1、下载yum-utils​​2、yumdownloader3、repotrack4、安装5、yumdownloader和repotrack的区别总结 前言 当开发者在联网环境下使用Linux时&#xff0c;可以轻松地通过yum或apt-get安装软件。然而&#xff0c;在公司和企业中&#xff0c;由于安全原因&#xff0c…

执行npm的时候报权限问题的解决方案

我们在执行npm操作的过程中&#xff0c;会出现以下权限问题&#xff0c;解决方案: 管理员身份 运行cmd 切换目录到要执行命令的文件下 再进行npm操作即可

社交媒体驱动的独立站流量增长:YouTube引流技巧

随着互联网的不断发展&#xff0c;视频内容在网上变得越来越受欢迎。YouTube作为世界上最大的视频分享平台之一&#xff0c;成为了吸引流量和观众的理想场所。对于跨境卖家来说&#xff0c;利用YouTube来增加独立站流量是一种有效的策略&#xff0c;可以增加知名度、吸引潜在客…

IDEA创建SpringBoot的多模块项目教程

最近在写一个多模块的SpringBoot项目&#xff0c;基于过程总了一些总结&#xff0c;故把SpringBoot多个模块的项目创建记录下来。 首先&#xff0c;先建立一个父工程&#xff1a; &#xff08;1&#xff09;在IDEA工具栏选择File->New->Project &#xff08;2&#xff0…

hypermesh学习总结(一)

1、hypermesh导入导出 2、hypermesh如何使用拓扑命令&#xff0c;连接多个几何体为一个&#xff1f; 3、hypermesh模式选择 分别有显示动力学模式explicit,标准模式Standard3D(静力学及模态等) 4、检查网格单元质量 5、基本平移旋转显示视角操作 6、更改网格划分最小…

【算法挨揍日记】day28——413. 等差数列划分、978. 最长湍流子数组

413. 等差数列划分 413. 等差数列划分 题目描述&#xff1a; 如果一个数列 至少有三个元素 &#xff0c;并且任意两个相邻元素之差相同&#xff0c;则称该数列为等差数列。 例如&#xff0c;[1,3,5,7,9]、[7,7,7,7] 和 [3,-1,-5,-9] 都是等差数列。 给你一个整数数组 nums…

链动2+1模式:创新营销引领白酒产业新潮流

在当今高度竞争的市场环境中&#xff0c;创新营销模式对于企业的发展至关重要。链动21模式作为一种独特的营销策略&#xff0c;将白酒产品与该模式相结合&#xff0c;充分发挥其优势&#xff0c;通过独特的身份晋升和奖励机制&#xff0c;快速建立销售渠道&#xff0c;提高用户…

【C语言.oj刷题】有序#整型矩阵元素查找##{思路+C源码}

目录 题目信息 题目分析&#xff1a; 法一&#xff1a; 遍历二维数组&#xff08;低效&#xff09; 思路 源码 局限性 法二&#xff1a; 对每一行二分查找&#xff08;有所提效&#xff09; 思路 源码 局限性 法三&#xff1a; 利用一切有利条件使用二分查找 思路 …

由两个独立的高增益运算放大器组成的运放芯片D258,可应用于音频信号处理系统上

D258是由两个独立的高增益运算放大器组成。可以是单电源工作&#xff0c;也可以是双电源工作,电源的电流消耗与电源电压大小无关。应用范围包括变频放大器、DC增益部件和所有常规运算放大电路。 主要特点&#xff1a; ● 可单电源或双电源 工作 ● 在一个封装内的两个经…

vue3项目安装eslint和prettier

【几乎最全/全网最长的 2 万 字】前端工程化完整流程&#xff1a;从头搭到尾&#xff08;vue3 vite qiankun docker tailwindcss iview......&#xff09;_前端工程化流程-CSDN博客 vue3tsvite项目中使用eslintprettierstylelinthusky指南 - 掘金 上面两篇文章相互结合操…

网络工程师网络配置经典例题(五)

1、配置SwitchA的单臂静态BFD特性 [SwitchA] bfd [SwitchA-bfd] quit [SwitchA] bfd 1 bind peer-ip 10.2.2.2 interface vlanif 10 source-ip 10.1.1.1 one-arm-echo [SwitchA-bfd-session-1] discriminator local 1 [SwitchA-bfd-session-1] min-echo-rx-interval 200 …