进程通信知识基础【Linux】——下篇

目录

前文

一,命名管道

创建命名管道

1. getline——c++库

2. unlink——系统接口

实践代码

common.hpp

client.cpp

server.cpp

Log.cpp

二,共享内存(system V接口)

1. 创建共享内存

shmget接口

2. 删除共享内存

常见ipc指令

shmctl接口

3. 映射到虚拟内存(挂起)

shmat接口

去关联

shmdt接口

小结:

三,信号量概念

概念引入 

小结


嘿!收到一张超美的风景图,希望你每天都能开心顺心

 

前文

经过进程池的实践(哈希思想应用【C++】(位图,布隆过滤器,海量数据处理面试题)-CSDN博客),我们对管道有了一定的理解,本篇继续给大家分享其余一些进程通信的知识。

一,命名管道

管道应用的一个限制就是只能在具有共同祖先(具有亲缘关系)的进程间通信。如果我们想在 不相关的进程之间交换数据,可以使用 FIFO文件来做这项工作,它经常被称为 命名管道
命名管道是一种 特殊类型文件

创建命名管道

在指令端创建

$  mkfifo   filename

在程序中创建

#include <sys/types.h>
#include <sys/stat.h>int mkfifo(const char *pathname, mode_t mode);

其中,pathname管道文件路径mode权限掩码,mkfifo函数返回值为0表示成功-1表示失败,错误原因存储在errno中。

下面我们来一个例子:

创建好一个命名管道后,执行下面指令,我们会遇到光标不动的现象。

echo "hello" > FilePipe

原因是:我们只是向命名管道进行写入没有打开命名管道的读端(从命名管道中读取数据), 进入了一种阻塞状态。(这也是管道的一种控制

解决方法也很简单,就是在另一个窗口,对命名管道进行读数据,这时就会中断写入的阻塞状态。

cat  <  FilePipe 

实践包含一些其他接口:

1. getline——c++库

istream& getline (istream& is, string& str, char delim);

其中,is是输入流,str是存储读取结果的字符串,delim是指定的分隔符(可选,默认为'\n'cin, scanf等是以空格和换行符为分隔符)。函数的返回值是输入流is的引用

getline函数的作用是从输入流is中读取一行文本,并将其存储到字符串str中。如果读取成功,则返回输入流is的引用。如果读取失败,则返回输入流的状态为false。

2. unlink——系统接口

int unlink(const char *pathname);

参数pathname为要删除的文件的路径名。当调用unlink接口时,系统会删除指定路径的文件。如果文件不存在或者无法访问,则会返回-1,并设置errno变量来指示错误类型。

下面头文件中: 

_COMM_H(名字自定义) 宏则是用来防止头文件的重复包含,通过定义这个宏可以在编译过程中检测到头文件是否被多次包含,避免出现重复定义的错误。

实践代码

common.hpp

#ifndef _COMM_H_
#define _COMM_H_
#include <iostream>
#include <vector>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include "Log.hpp"using namespace  std;#define MOODE 0666
#define SIZE 128
#define CHNUMS 3string Pipename = "FilePipe";
string PipeAddress = "./FilePipe";#endif

client.cpp

#include "common.hpp"int main()
{// 1. 客户向服务端,传输请求int fd = open(PipeAddress.c_str(), O_WRONLY);if (fd < 0 ){cout << "open fail" << endl;}string buff;while (1){cout << " Please set your information :> ";getline(cin, buff);  //getline接口的优势在于它可以读取一行文本,并且自动将换行符(\n)作为行结束符write(fd, buff.c_str(), buff.size());}// 关闭命名管道close (fd);// 用户信息读取完后,需要我们删除这个命名管道文件。unlink(Pipename.c_str());//unlink接口是用于删除一个指定的文件或符号链接的系统调用。 return 0;
}

server.cpp

#include "common.hpp"
#include <sys/wait.h>static void Getmessage(int fd) // 设置成静态函数的目的是,让其他文件,无法使用该函数
{char buff[SIZE];Log("处理数据开始", Test) << "[" << getpid() << "] "<< " step 3 " << endl;while (1){memset(buff, '\0', sizeof(buff));ssize_t byte = read(fd, buff, sizeof(buff) - 1);if (byte > 0){cout << "[" << getpid() << "] " << buff << endl;}else if ( byte == 0){cout << " write close " << endl;break;}else{perror(" read fail");cout << "[" << getpid() << "] " << " read error "  << endl;break;}}
}int main()
{// 1. 创建命名管道if (mkfifo(PipeAddress.c_str(), MOODE) < 0 ){perror( " mkfifo fail ");}Log("创建命名管道成功", debug) << "step 1" << endl;// 2. 文件操作int fd = open(PipeAddress.c_str(), O_RDONLY);if (!fd){perror(" open fail");exit(-1);}Log("文件操作成功", debug) << "step 2" << endl;pid_t id;vector<int> FdList;for (int i = 0; i < CHNUMS; i++){id = fork();if (id == 0){Getmessage(fd);exit(1);  // 子进程完美退出,等待父进程接收}}// 父进程接受子进程退出int status = 0;for (int i = 0; i < CHNUMS; i++){// waitpid(FdList[i], nullptr, 0);  这样子写会些坑,不知道哪一个子进程先状态改变waitpid(-1, &status, 0); // -1则是随机等待一个子进程状态改变} // 4. 关闭文件close(fd);unlink(PipeAddress.c_str());Log("关闭文件", warning) << "step 4" << endl;return 0;
}

Log.cpp

#ifndef _LOG_
#define _LOG_
#include <iostream>
#include <ctime>
#include <string>
using namespace std;#define debug 0
#define warning 1
#define Test 2string list_level[3] = {"debug","warning","Test"  
};ostream&  Log(const char* str, int level)
{cout <<  str << " | " << (unsigned)time(0) << " | " << list_level[level] << " ";return cout;
}#endif

下面是上面代码功能的形象图:

二,共享内存(system V接口)

共享内存是一种操作系统进程通信的方式,它允许多个进程共享同一块物理内存区域,从而实现高效的数据交换和共享。

共享内存的原理是将一块物理内存映射到多个进程的虚拟地址空间中,这样多个进程就可以直接读写这块内存,而不需要通过复制数据或者消息传递等方式进行通信

共享内存通常使用信号量来实现进程间的同步和互斥访问。

多个进程共享一块物理内存,操作系统一定得这个操作进行有序管理,而一旦涉及管理,必然要进行 先描述,再组织。

所有共享内存 =  共享内存块 +  对应共享内存块的内核数据结构。

1. 创建共享内存

shmget接口

返回值:一个操作系统运行时,肯定不只一个共享内存,众多的共享内存也被一个内核数据结构管理起来,而返回值就类似文件描述中的fd

1.   int shmflg:  IPC_CREAT(单独用以0替代) and IPC_EXCL 两个宏,前者单独用,共享内存不存在则创建;存在,则返回之。    后者,单独用没有意义,两者通过按位与一起用,底层不存在则创建;存在则出错返回(意义:保证每次共享内存都是最新的)。

2.   key_t key: 我们知道一个操作系统中有众多的共享内存,而key通过特殊的算法规则处理,形成唯一的通行码,找到精确共享内存。

那如何获取 key,通过ftok接口(就是一个对数据进行算法规则处理)。

 

  • pathname:  一个我们可以访问的路径(操作系统会访问其inode值(一个存储标识值)); 
  • proj_id :    就是一个int值。如果想获取一个相同的key值,proj_id也得相同。

返回值:-1失败;大于0则是key值。

3.   size_t size :   共享空间的字节大小。最后是页(4096)的整数倍。原因:假设要4097,则操作系统会创建8192字节,但中间空间我们又无法访问这就是浪费资源了。

2. 删除共享内存

输入指令: 查看共享内存资源

手动删除:

ipcs -m      

然后输入:ipcrm  -m  shmid值

 这里我们要注意的是:共享内存的生命周期随内核!!,除非重启!

perms: 权限值,为0时,谁也无法访问该共享内存,需要在shmget时需要输入权限,比如: shmget(123,  4096 , IPC_CREAT | IPC_EXCL | 0666),权限同文件一样

常见ipc指令

1. ipcs - 显示系统中的IPC资源信息
2. ipcrm - 删除IPC资源
3. ipcs -q - 显示消息队列信息
4. ipcs -s - 显示信号量信息
5. ipcs -m - 显示共享内存信息 

代码删除:

shmctl接口

cmd:  可以理解为功能选项,我们可以选择删除,获取共享空间属性信息等等。IPC_STAT, IPC_RMID等等

shmid:理解为共享内存的标识符吧。

*buf  :  这是管理共享内存的数据结构指针,可用通过buf获取或者修改其属性。

返回值: -1表示失败。

3. 映射到虚拟内存(挂起)

shmat接口

shmid:  共享内存唯一的id 

shmaddr:  去设置一个虚拟地址。(由于我们不清楚虚拟地址的使用情况,这里建议null/nullptr,让计算机来产生

shmflg: 挂接方式,以只读(SHM_R默认0),只写(SHM_W),还是读写(SHM_R | SHM_W )方式挂接。

返回值: 就是计算机返回共享内存虚拟地址的开头; 返回0则失败。

当一旦挂起成功,进程关联数就会增加

去关联

shmdt接口

shmaddr:   共享内存虚拟地址起始地址。 

返回值:-1失败; 0成功,成功删除后同时,进程关联数减一。

成功创建共享内存后位置分布的逻辑图

代码示例:

#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>int main() {key_t key = ftok("shmfile",65);  // 创建一个keyint shmid = shmget(key,1024,IPC_CREAT|0666);  // 创建共享内存区char *str = (char*) shmat(shmid,(void*)0,0);  // 将共享内存区连接到当前进程的地址空间printf("Write data : ");gets(str);printf("Data written in memory: %s\n",str);shmdt(str);  // 分离共享内存区shmctl(shmid,IPC_RMID,NULL);  // 删除共享内存区return 0;
}

这里介绍一个比较重要的格式打印数据的接口: snprintf()接口 

小结:

1. 共享内存是进程通信(IPC)中,速度最快的。因为这个方法不需要过多的拷贝数据,而且不用经过操作系统,在用户层直接读取修改。

2. 由于共享内存没有访问控制(读写端独立),容易引发并发问题(两端数据不一致问题)。

三,信号量概念

概念引入 

小结

我们需要理解这个概念

没理解?没事,这个我们在多线程里,用代码的形式进行解释。

下期预告:信号!!

结语

   本小节就到这里了,感谢小伙伴的浏览,如果有什么建议,欢迎在评论区评论,如果给小伙伴带来一些收获请留下你的小赞,你的点赞和关注将会成为博主创作的动力

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

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

相关文章

Spark编程实验二:RDD编程初级实践

目录 一、目的与要求 二、实验内容 三、实验步骤 1、pyspark交互式编程 2、编写独立应用程序实现数据去重 3、编写独立应用程序实现求平均值问题 4、三个综合实例 四、结果分析与实验体会 一、目的与要求 1、熟悉Spark的RDD基本操作及键值对操作&#xff1b; 2、熟悉使…

【算法与数据结构】LeetCode55、45、跳跃游戏 I 、II

文章目录 一、跳跃游戏I二、跳跃游戏II三、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、跳跃游戏I 思路分析&#xff1a;本题目标是根据跳跃数组的元素&#xff0c;判断最终能够到达数组末端。我们引入了一个跳跃范围…

解锁终端安全的钥匙:深度了解迅软DSE桌面管理系统

随着信息化的快速发展&#xff0c;企业内部计算机终端数量不断攀升&#xff0c;成为网络整体安全管理的关键环节。越来越多的企业认识到终端安全管理的重要性&#xff0c;纷纷采取综合规划来应对这一挑战。为了满足广大用户对桌面终端管理的需求&#xff0c;迅软DSE推出了一套全…

『K8S 入门』二:深入 Pod

『K8S 入门』二&#xff1a;深入 Pod 一、基础命令 获取所有 Pod kubectl get pods2. 获取 deploy kubectl get deploy3. 删除 deploy&#xff0c;这时候相应的 pod 就没了 kubectl delete deploy nginx4. 虽然删掉了 Pod&#xff0c;但是这是时候还有 service&#xff0c…

Python 爬虫之简单的爬虫(三)

爬取动态网页&#xff08;上&#xff09; 文章目录 爬取动态网页&#xff08;上&#xff09;前言一、大致内容二、基本思路三、代码编写1.引入库2.加载网页数据3.获取指定数据 总结 前言 之前的两篇写的是爬取静态网页的内容&#xff0c;比较简单。接下来呢给大家讲一下如何去…

若依 ruoyi-vue3 集成aj-captcha实现滑块、文字点选验证码

目录 0. 前言0.1 说明 1. 后端部分1.1 添加依赖1.2. 修改 application.yml1.3. 新增 CaptchaRedisService 类1.4. 添加必须文件1.5. 移除不需要的类1.6. 修改登录方法1.7. 新增验证码开关获取接口1.8. 允许匿名访问 2. 前端部分&#xff08;Vue3&#xff09;2.1. 新增依赖 cryp…

python【matplotlib】鼠标拖动滚动缩放坐标范围和拖动图例共存

背景 根据前面的博文&#xff1a; python【matplotlib】画图鼠标缩放拖动动态改变坐标轴范围 和Python【Matplotlib】图例可拖动改变位置 两个博文&#xff0c;博主考虑了一下&#xff0c;如何将两者的功能结合起来&#xff0c;让二者共存。 只需根据Python【Matplotlib】鼠标…

PIC单片机项目(4)——基于PIC16F877A的温度光照检测装置

1.功能设计 基于PIC16F877A单片机&#xff0c;使用DS18B20进行温度测量&#xff0c;使用光敏电阻进行光照测量&#xff0c;将测量值实时显示在LCD1602屏幕上&#xff0c;同时可以设定光照阈值和温度阈值。当温度大于阈值&#xff0c;则蜂鸣器报警&#xff0c;当光照小于阈值&am…

ES-脚本

脚本 简单使用 POST product/_update/2 {"script": {"source": "ctx._source.salary1" #将薪水字段的值 1} }预定义变量 POST product/_update/2 {"script": {"lang": "painless","source": "…

[C++] 多态(下) -- 多态原理 -- 动静态绑定

文章目录 1、多态原理2、动态绑定和静态绑定3、单继承和多继承关系的虚函数表3.1 单继承中的虚函数表5.2 多继承中的虚函数表 上一篇文章我们了解了虚函数表&#xff0c;虚函数表指针&#xff0c;本篇文章我们来了解多态的底层原理&#xff0c;更好的理解多态的机制。 [C] 多态…

flask搞个简单登录界面

登录界面 直接放上login.html模板&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Lo…

windows 安装jenkins

下载jenkins 官方下载地址&#xff1a;Jenkins 的安装和设置 清华源下载地址&#xff1a;https://mirrors.tuna.tsinghua.edu.cn/jenkins/windows-stable/ 最新支持java8的版本时2.346.1版本&#xff0c;在清华源中找不到&#xff0c;在官网中没找到windows的下载历史&#xff…

Nginx七层代理,四层代理 + Tomcat多实例部署

目录 1.tomcat多实例部署 准备两台虚拟机 进入pc1 pc2同时安装jdk 进入pc1 pc2安装tomcat PC1配置&#xff08;192.168.88.50&#xff09; 安装tomcat多实例 tomcat2中修改端口 启动tomcat1 tomcat2 分别在三个tomcat服务上部署jsp的动态页面 2.nginx的七层代理&…

记录一次云服务器被攻击事件

今天去登录华为云平台的时候&#xff0c;发现服务器的cpu涨到了百分之九十九&#xff0c;这个也太不正常了&#xff0c;我自己就只部署了一个页面&#xff0c;怎么会飚这么高呢&#xff1f; 然后&#xff0c;我就去找原因&#xff0c;使用top命令&#xff0c;去查看到底是谁占用…

JDK21+HADOOP3.2.2+Windows安装步骤

哈哈哈 最近转战大数据这块了&#xff0c;分享一下hadoop3.2.2的安装步骤 借鉴了不少大佬的文章&#xff0c;如有雷同&#xff0c;都是大佬们的 1.JDK安装 我选择的是JDK21 以下是下载网址和截图&#xff0c;这个没有太多的&#xff0c;一般下载最新的就可以 JDK: Java Down…

【C语言】自定义类型:结构体深入解析(一)

&#x1f308;write in front :&#x1f50d;个人主页 &#xff1a; 啊森要自信的主页 ✏️真正相信奇迹的家伙&#xff0c;本身和奇迹一样了不起啊&#xff01; 欢迎大家关注&#x1f50d;点赞&#x1f44d;收藏⭐️留言&#x1f4dd;>希望看完我的文章对你有小小的帮助&am…

编辑器Sublime text 常用快捷命令 列模式 替换空行

平替notepad 下载可取官网 www.sublimetext.com 据说可以无限试用&#xff0c;没有功能限制 1、快速删除空行 ctrl h选择正则表达式 .*Find输入&#xff1a; ^(\t)*$\nReplace输入&#xff1a;点击Replace All 2、快速选择指定字符 用鼠标选中alt f3修改 3、列编辑模式 ct…

WEB渗透—PHP反序列化(五)

Web渗透—PHP反序列化 课程学习分享&#xff08;课程非本人制作&#xff0c;仅提供学习分享&#xff09; 靶场下载地址&#xff1a;GitHub - mcc0624/php_ser_Class: php反序列化靶场课程&#xff0c;基于课程制作的靶场 课程地址&#xff1a;PHP反序列化漏洞学习_哔哩…

win10环境下git安装和基础操作

简述 关于git的作用就不多赘述了&#xff0c;配合GitHub&#xff0c;达到方便人们日常项目维护和管理&#xff0c;每一次项目增删改查都可以看的清清楚楚&#xff0c;方便团队协作和个人项目日常维护。 下载git 首先我们自然是要到官网下载git&#xff0c;下载地址为https:/…

无框架Java转go语言写http与tcp请求

项目地址 https://github.com/cmdch2017/http_tcpServer 项目结构 如何快速上手 http篇 1、controller包就相当于RestController&#xff0c;这里返回了一个Person对象&#xff0c;当你需要新建一个接口时&#xff0c;再新写一个func仿照下面的方法就行了 package control…