【Linux】进程间通信方式②——文件共享映射(附图解与代码实现)

news2024/11/17 5:32:10

我们来简单了解下文件共享映射的定义:通过映射文件,使用映射机制,实现资源共享,完成进程通信

具体是如何实现的呢?跟随着这篇博客,我们来看一看

进程通过文件共享映射实现通信的具体步骤

  1. 由某一进程创建映射文件
  2. 该进程通过使用frtuncate函数将文件截断至我们想要的大小(关于frtuncate函数的介绍请看注释①)
  3. 在进程内申请与映射文件大小相同的映射内存,并将映射文件中的内容通过共享映射的方式加载到被申请的映射内存当中,该步骤通过mmap函数实现(关于mmap函数的介绍请看注释②)。要注意的是,mmap函数的映射方式有两种,分别是私有映射和共享映射(关于私有映射和共享映射的区别请看注释③)
  4. 其余进程使用被创建出的映射文件描述符,通过mmap函数也和该映射文件进行共享映射,这样就实现了进程之间的通信
  5. 通信完成后就要释放映射,释放映射通过munmap函数实现(关于munmap函数的介绍请看注释④)

PS:映射内存申请在进程用户层的库内存中,因为库内存的大小会改变

注释①:简单了解一下ftruncate函数

头文件#include<unistd.h>、#include<sys/types.h>
功能

如果文件初始大小小于我们所要求的大小,便在后面不断填充'\0',直到文件截断至我们要求的大小;

如果文件初始大小大于我们所要求的大小,便在文件目标大小处加入'\0'来截断文件并删除后面的内容,使文件达到我们要求的大小

语法int ftruncate(文件描述符 , 想要截断到多大)
返回值成功则返回 0,失败返回  -1, 错误原因存于errno

参数介绍:

参数变量类型解释
文件描述符int有效文件描述符,一般由open函数返回
想要截断到多大off_t将指定的文件的大小改为指定的大小

注释②:简单了解一下mmap函数

头文件#include<sys/mman.h>
功能在进程内申请映射内存,并将映射文件中的内容加载到系统申请的映射内存当中
语法void *mmap(起始地址 , 映射内存大小 , 内存权限 , 映射方式 , 映射文件描述符 , 偏移量);
返回值成功执行时,mmap函数返回映射内存的起始地址
失败时,mmap函数返回MAP_FAILED [ 其值为(void *) -1 ]

参数介绍:

参数变量类型解释
起始地址void*我们希望映射内存从哪里开始被创建,一般传NULL,表示让系统自主申请空间
映射内存大小size_t一般直接传入映射文件的大小,注意这个地方不能填0,否则直接失败
内存权限intPROT_EXEC //页内容可以被执行      PROT_READ //页内容只读PROT_WRITE //页可以只写               PROT_NONE //页不可访问
映射方式intMAP_PRIVATE//私有映射     MAP_SHARED//共享映射(具体请看注释③)
映射文件描述符int有效文件描述符,一般是由open函数返回
偏移量off_t被映射对象内容的起点,需要注意的是,内存是以页为单位的,所以偏移量必须是一页或者一页的整数倍

PS:映射成功后这个映射文件描述符就没用了,因为后续的修改是通过sync同步机制,而不是通过read,write函数来实现,所以映射成功后就可以直接close(映射文件描述符)

注释③:私有映射与共享映射的区别

映射方式功能
私有映射 MAP_PRIVATE私有映射又叫只读映射,是指仅将映射文件中的内容拷贝到进程的映射内存之中,后续进程对映射内存中内容的修改不会影响到映射文件中的内容
共享映射 MAP_SHARED共享映射中有一种机制叫做sync同步机制,对一端的修改会实时同步到另一端,这也是通过文件共享映射实现进程通信的基础

注释④:简单了解一下munmap函数

头文件#include <sys/mman.h> 
功能内存映射完毕后,调用munmap函数解除内存映射,释放相关资源。
语法int munmap(映射内存起始地址, 映射内存的大小);
返回值成功返回0,失败返回-1

参数介绍:

参数变量类型解释
映射内存起始地址void*mmap函数的返回值
映射内存的大小size_t其实也就是映射文件的大小

为什么说映射内存的大小其实就是映射文件的大小呢?

我来做一个情景假设,假设我提前创建了一个映射文件,大小为0,文件描述符为fd

然后我写下面这样一行代码,直接申请一个大小为4096的映射内存,大家猜一下,这行代码能不能通过

void* ptr = mmap(NULL , 4096 , PROT_WRITE , MAP_SHARED , fd , 0);

这段代码是可以通过的,你确实申请出来了这样大小的一块映射内存,但是你想要使用时就会报错,因为操作系统后面发现你骗了他,你映射文件大小为0,你用个屁的映射内存啊。

就像你拿 “给哥们过生日” 当理由找老婆要钱的时候,你老婆一开始确实会划出一部分钱来专门给你用来给哥们过生日,但后面你老婆一个电话打过去问你哥们,结果发现你哥们生日还有大半年的时候,她就会直接就把这部分钱收回来不让你用,并且给你几个最爱吃的大逼兜作为警告,这是一个道理

你映射文件大小是多少才能使用多大的映射内存,你映射文件大小为1,你即使申请出来100大小的映射内存,你也只能用1的大小,你用其他99大小的映射内存就属于访问越界,这就是总线错误,系统会发出SIGBUS信号来直接干掉你这个进程

进程通过文件共享映射实现通信的代码实现与图解

这里需要两个进程,一个读一个写,我们创建两个.c文件,分别为map_write.c和map_read.c

代码及讲解如下所示:

写进程:map_write.c

//map_write.c

#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include<fcntl.h>
#include<sys/mman.h>
#include<sys/stat.h>

/*设置一个定时器*/
#define timeout 1

/*定义一个结构体,映射文件里存放的就是结构体消息*/
typedef struct
{
	int code;
	char msg[100];
}msg_t;

int main(void)
{
	/*1.创建映射文件,读写打开*/
	int fd = open("MAP" , O_RDWR|O_CREAT , 0664);
	/*2.由于是往文件里写结构体类型的消息,所以要将文件拓展至一个结构体的大小*/
	ftruncate(fd , sizeof(msg_t));
	/*3.建立映射关系*/
	/*由于映射文件里是结构体类型的消息,所以要定义一个结构体类型的指针来接取返回值*/
	msg_t* ptr = NULL;
    //如果映射创建失败,程序直接退出
	if((ptr = mmap(NULL , sizeof(msg_t) , PROT_READ|PROT_WRITE , MAP_SHARED , fd , 0)) == MAP_FAILED)
	{
		perror("映射关系建立失败!\n");
		exit(0);
	}
	/*映射关系建立成功,关闭文件*/
	close(fd);
	/*初始化结构体里面的内容*/
	ptr->code = 0;
	bzero(ptr->msg , sizeof(ptr->msg));
	/*循环向映射文件内写入内容*/
	while(1)
	{
		ptr->code++;
		sprintf(ptr->msg , "this is a test message , code = %d\n" , ptr->code);
		sleep(timeout);
	}
	/*关闭映射*/
	munmap(ptr , sizeof(msg_t));
	exit(0);
}

读进程:map_read.c

//map_read.c

#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include<fcntl.h>
#include<sys/mman.h>
#include<sys/stat.h>

/*设置一个定时器*/
#define timeout 1

/*定义一个结构体,映射文件里存放的就是结构体消息*/
typedef struct
{
	int code;
	char msg[100];
}msg_t;

int main(void)
{
	/*先打开文件*/
	int fd = open("MAP" , O_RDWR);
	/*由于该进程是读取内容,所以不能扩展映射文件的大小,否则会覆盖文件里的内容*/
	/*建立映射关系*/
	/*由于映射文件里是结构体类型的消息,所以要定义一个结构体类型的指针来接取返回值*/
	msg_t* ptr = NULL;
	if((ptr = mmap(NULL , sizeof(msg_t) , PROT_READ|PROT_WRITE , MAP_SHARED , fd , 0)) == MAP_FAILED)
	{
		perror("读进程映射关系建立失败!\n");
		exit(0);
	}
	/*映射关系建立成功,关闭文件*/
	close(fd);
	/*循环向映射文件内读取内容*/
	while(1)
	{
		printf("%s\n" , ptr->msg);
		sleep(timeout);
	}
	/*关闭映射*/
	munmap(ptr , sizeof(msg_t));
	exit(0);
}

最终结果

以上就是本篇博客的全部内容了,大家有什么地方没有看懂的话,可以在评论区留言给我,咱要力所能及的话就帮大家解答解答

今天的学习记录到此结束啦,咱们下篇文章见,ByeBye!

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

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

相关文章

【湖科大教书匠】计算机网络随堂笔记第2章(计算机网络物理层)

目录 2.1、物理层的基本概念 2.2、物理层下面的传输媒体 导引型传输媒体 同轴电缆 双绞线 光纤 电力线 非导引型传输媒体 无线电波 微波 红外线 可见光 2.3、传输方式 串行传输和并行传输 同步传输和异步传输 单向通信&#xff08;单工&#xff09;、双向交替通信&#xf…

【LeetCode-简单题】110. 平衡二叉树

文章目录 题目方法一&#xff1a;后序递归 题目 方法一&#xff1a;后序递归 递归遍历的同时判断是否是平衡二叉树&#xff0c;如果不是&#xff0c;就置为-1&#xff0c;如果是 就正常做递归求最大深度 参考图解网址 判断平衡二叉树 class Solution {public boolean isBalanc…

誉天在线项目-放大招-Vue3集成RichText富文本客户端组件QuillEditor

背景 开发中我们需要填写图文内容&#xff0c;就是含有图片和文字&#xff0c;html标准组件中是没有的。都是第三方来实现&#xff0c;就需要我们去集成。 有早期的fckEditor、ckEditor等&#xff0c;新的我们使用了vue框架&#xff0c;市场又推出了quillEditor。下面我们就在…

【【萌新的SOC学习之绪论】】

萌新的SOC学习之绪论 Vitis 统一软件平台的前身为 Xilinx SDK&#xff0c;从 Vivado 2019.2 版本开始&#xff0c;Xilinx SDK 开发环境已统一整合 到全功能一体化的 Vitis 中。Vitis 开发平台除了启动方式、软件界面、使用方法与 SDK 开发平台略有区别&#xff0c; 其他操作几…

使用acme.sh申请免费ssl证书(Cloudflare方式API自动验证增加DNS Record到期证书到期自动重新申请)

下载acme.sh curl https://get.acme.sh | sh -s emailmyexample.comcd ~/.acme.sh/获取Cloudflare密钥 Preferences | Cloudflare 登录选择账户详情选择API Token选择创建令牌选择区域DNS模板&#xff0c;并设置编辑写入权限生成并复制令牌备用回到首页概览界面下部获取账号…

【RabbitMQ实战】3分钟在Linux上安装RabbitMQ

本节采用docker安装RabbitMQ。采用的是bitnami的镜像。Bitnami是一个提供各种流行应用的Docker镜像和软件包的公司。采用docker的方式3分钟就可以把我们想安装的程序运行起来&#xff0c;不得不说真的很方便啊&#xff0c;好了&#xff0c;开搞。使用前提&#xff1a;Linux虚拟…

3D设计软件Rhinoceros 6 mac 犀牛6中文版功能特征

Rhinoceros Mac中文版是一款3D设计软件“犀牛”&#xff0c;在众多三维建模软件中&#xff0c;Rhinoceros mac因为其体积小、功能强大、对硬件要求低而广受欢迎&#xff0c;对于专业的3D设计人员来说它是一款非常不错的3D建模软件&#xff0c;Rhinoceros Mac中文版能轻易整合3D…

苹果手机短信删除了怎么恢复?3种有效方法介绍

手机短信是一种即时通信方式&#xff0c;人们可以使用短信来达到快速传递信息的目的。在没有网络或者网络不稳定的时候&#xff0c;短信仍然可以做到发送和接收&#xff0c;这弥补了其他网络通信软件的缺点。 所以说&#xff0c;手机短信仍然是我们生活中不可缺少的一部分。当…

【rtp】mid 扩展: RtpMid 字符串扩展的解析和写入

mid 是uint8_t 类型? 扩展填写的是字符串,读取字符串后atoi 转 uint8_t : webrtc 看起来是个字符串:写入 扩展的值是改变了: 这里是更新扩展的长度: 新的大小小于原来的,没有缩减内存,而是对于多余的置位0了:if (len < current_len) {memset(

基于SSM的高校图书馆个性化服务的设计与实现(有报告)。Javaee项目。

演示视频&#xff1a; 基于SSM的高校图书馆个性化服务的设计与实现&#xff08;有报告&#xff09;。Javaee项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;通过S…

如何在低代码平台中应用可视化编程

可视化编程&#xff0c;亦即可视化程序设计&#xff1a;以“所见即所得”的编程思想为原则&#xff0c;力图实现编程工作的可视化&#xff0c;即随时可以看到结果&#xff0c;程序与结果的调整同步。可视化编程的理念来源于可视化技术&#xff0c;它指的是一种把计算机程序中的…

深度学习在视频直播美颜sdk中的应用

视频直播美颜SDK是一类用于实时视频美颜处理的工具包&#xff0c;它们利用深度学习算法来提高视频直播中的主播和观众的外观吸引力。本文将深入探讨深度学习在视频直播美颜sdk中的应用&#xff0c;以及这些应用对直播行业的重要性。 一、人脸检测与关键点定位 通过卷积神经网…

Centos7安装go解释器

Centos7安装go解释器 下载解压go压缩包编辑go变量结果验证 下载解压go压缩包 # 下载 wget -c https://go.dev/dl/go1.20.2.linux-amd64.tar.gz# 解压到指定目录 tar xvf go1.20.2.linux-amd64.tar.gz -C /usr/local/编辑go变量 /etc/profile.d/go.sh # 指定go执行程序位置 e…

多线程进阶:常见的锁策略、CAS

之前我们所了解的属于多线程的初阶内容。今天开始&#xff0c;我们进入多线程进阶的学习。 锁的策略 乐观锁 悲观锁 这不是两把具体的锁&#xff0c;应该叫做“两类锁” 乐观锁&#xff1a;预测锁竞争不是很激烈&#xff08;这里做的工作可能就会少一些&#xff09; 悲观锁…

【操作系统笔记六】内存分配

内存对齐 问题&#xff1a;为什么需要内存对齐呢&#xff1f; 主要原因是为了兼容&#xff0c;为了让程序可以运行在不同的处理器中&#xff0c;有很多处理器在访问内存的时候&#xff0c;只能从特定的内存地址读取数据。换个说法就是处理器每次只能从内存取出特定个数字节的数…

WKB近似

WKB方法用于研究一种特定类型的微分方程的全局性质 很有用这种特定的微分方程形如&#xff1a; 经过一些不是特别复杂的推导&#xff0c;我们可以得到他的WKB近似解。 该近似解的选择取决于函数和参数的性质同时&#xff0c;我们默认函数的定义域为当恒大于零,时&#xff1a; 当…

淘宝/天猫获得淘宝商品详情(关键词搜索,店铺所有商品)API接口返回值说明

淘宝API接口&#xff0c;简单而言&#xff0c;就是一套工具&#xff0c;可以帮助你与淘宝平台的数据与功能进行智能对接。它能够让你的店铺信息、商品信息、用户数据等信息实现高效流通&#xff0c;帮助你更好地理解客户需求 我们深知数据安全的重要性&#xff0c;因此&#x…

【MySQL】MySQL中的复制技术是什么?它有哪些组成部分?

什么是复制&#xff08;Replication&#xff09;MySQL复制架构感谢 &#x1f496; 什么是复制&#xff08;Replication&#xff09; 复制技术是MySQL高级特性的基础。它可以将数据从一个 MySQL 实例复制到另一个实例&#xff0c;从而实现数据的同步和备份。 MySQL复制架构 以…

Ansys Zemax | 如何设计光谱仪——理论依据

光谱学是一种无创性技术&#xff0c;是研究组织、等离子体和材料的最强大工具之一。本文介绍了如何利用近轴元件建立透镜—光栅—透镜(LGL)光谱仪模型&#xff0c;使用OpticStudio的多重结构( Multiple Configurations )、评价函数 ( Merit Functions )和ZPL宏等先进功能完成了…

八、伯努利朴素贝叶斯算法(Bernoulli NB,Bernoulli Naive Bayes)(有监督学习)

Bernoulli Naive Bayes&#xff1a;用于多元伯努利模型的Naive Bayes分类器 一、算法思路 与多项式分类器一样&#xff0c;该分类器也适用于离散数据。不同之处在于&#xff0c;多项式分类器适用于出现次数&#xff0c;而伯努利分类器则适用于二进制/布尔特征。 二、官网API…