Linux通信--构建进程通信IPC的方案之共享内存|实现使用共享内存进行serverclient通信

news2024/7/6 18:56:36

共享内存是最快的IPC形式。一旦这样的内存映射到共享它的进程地址空间,这些进程间数据传递不再涉及到内核,即进程不再通过执行进入内核的系统调用来传递彼此的数据。

目录

一、共享内存的原理

二、使用共享内存

三、共享内存函数

1.shmget(用来创建共享内存)

2.shmat(将共享内存和进程地址空间关联)

3.shmctl(用于控制共享内存)

4.shmdt(将共享内存段与当前进程脱离)

四、共享内存server&client通信测试

①创建共享内存

 ②关联共享内存和进程

//2-3 进行通信

③取消关联进程和共享内存

④关闭共享内存


一、共享内存的原理

  • 1.在物理内存中开辟一块空间
  • 2.让不同的进程通过页表将该空间映射到自己的进程虚拟地址空间中
  • 3.不同进程通过操作自己进程虚拟空间中的虚拟地址,来操作共享内存。

进程A和B都通过各自的页表将自己的虚拟地址和物理地址进行对应,进程A操作虚拟地址写入数据,保存在物理内存,进程B读取该物理内存。

二、使用共享内存

共享内存在物理地址空间上,是在共享区中。

  1. 创建共享内存
  2. 关联进程--将进程的虚拟地址和共享内存的地址通过页表建立映射关系
  3. 通信
  4. 取消关联进程--通过将进程中页表的key-value删除
  5. 共享内存释放

三、共享内存函数

上图表示进程A和进程B可以通过共享内存来通信,同样C和D也可以通过另一块共享内存通信。所以在系统中,一定同时存在多个共享内存,os需要对这些内存块做管理,所以使用一个结构体,里面存放共享内存的各个属性

所以 共享内存 == 共享内存的内核数据结构 + 真正开辟的物理空间

1.shmget(用来创建共享内存)

原型:int shmget(key_t key,size_t size,int shmflg)

参数:key 这个共享内存段名字 size 共享内存大小 shmflg 由九个权限标志构成,用法的mode一样

返回值:成功返回一个非负整数,即共享内存段的标识码,失败返回-1

其中key_t key 是由ftok算法生成的随机值,具有唯一性,ftok函数如下:

key_t  ftok(const char * pathname,int proj_id)

形参:pathname 传入一个地址  proj_id 输入一个数字 这两个值可以任意设置,但是在通信双方必须是相同的,具体地,A进程调用ftok生成key,将key放入struct shm中,B也生成相同的key,B用这个key去struct shm去匹配,匹配成功,就找到了共享内存。

shmflg宏含义
IPC_CREAT单独使用时,创建一个共享内存,如果不存在就直接创建,如果存在就获取已有的共享内存起始地址返回
IPC_EXCL需要依赖IPC_CREAT使用,如果不存在则创建共享内存,如果存在立马退出报错返回

2.shmat(将共享内存和进程地址空间关联)

原型:void * shmat(int shmid,const void * shmaddr,int shmflg);

参数: shmid 共享内存标识 shmaddr 指定连接的地址 shmflg它的两个可能取值是SHM_RND 和SHM_RDONLY

返回值:成功返回一个指针,指向共享内存的起始地址,失败返回-1(类似于malloc)

说明:shmaddr为null,os自动选择一个地址,

           shmaddr不为null,且shmflg无SHM_RND标记,则以shmaddr为连接地址

         shmaddr不为null,且shmflg设置了SHM_RND标记,则连接的地址会自动向下调整 shmlba的整数倍

            shmflg = SHM_RDONLY 表示连接操作用来只读共享内存

3.shmctl(用于控制共享内存)

原型: int shmctl(int shmid,int cmd,struct shmid_ds * buf);

参数:shmid由shmget返回的共享内存标识码

            cmd:将要采取的动作(有三个可能取值如下表)

           buf:指向一个保存着共享内存的模式状态和访问权限的数据结构

返回值:成功返回0,失败返回-1

命令说明
IPC_STAT将shmid_ds结构中的数据设置为共享内存的当前关联值
IPC_SET在进程有足够权限的前提下,将共享内存的当前关联值设置为shmid_ds数据结构中给出的值
IPC_RMID删除共享内存段


4.shmdt(将共享内存段与当前进程脱离)

原型:int shmdt(const void * shmaddr);

参数:shmaddr:由shmat所返回的指针

成功返回0,失败返回-1

注:将共享内存与当前进程脱离不等于删除共享内存段 

四、共享内存server&client通信测试

使用共享内存通信的步骤:创建共享内存,关联进程和共享内存,进行通信,取消关联,删除共享内存

 创建4个文件:server.cc,client.cc,common.hpp,makefile。server实现写入,client实现读取

makefile要生成两个目标文件server,client,可以这样写:

.PHONY:all
all:server client
client:client.c comm.c
 gcc -o $@ $^
server:server.c comm.c
 gcc -o $@ $^
.PHONY:clean
clean:
 rm -f client server

common.hpp中声明和定义一些客户端和服务端公有的函数,如下:

这个文件中主要实现创建共享内存,关联进程和取消关联,共享内存释放。

①创建共享内存

  1. 首先,创建共享内存,使用shmget
  2. 其中有一个key,使用ftok生成,在两端调用即可\
  3. 通信的时候,一个进程创建共享内存,一个进程获取.
  4.   共享内存创建时,是按字节为单位。
//创建共享内存,要知道k和这个共享内存的大小
int createShm(key_t k, int size)
{
    //创建的时候,最好创建全新的
    int shmid = shmget(k,gsize,IPC_CREAT|IPC_EXCL);
    if(shmid == -1)
    {
       //创建失败
        exit(2);
    }
    
    return shmid;
}

//创建成功,一个进程获取
int getShm(key_t,int size)
{
    int shmid = shmget(k,gsize,IPC_CREAT);
    return shmid;
}

从上述两个函数,一个创建一个获取,只是shmflg不同,所以可以封装为一个函数

//static 只在本文件内有效
static int createShmHelper(int k, int size,int flag)
{
    int shmid = shmget(k,gsize,flag);
    if(shmid == -1)
    {
        exit(2);
    }

    return shmid;
}



int createShm(key_t k,int size)
{
      //创建的时候注意加权限
      umask(0);
      return createShmHelper(key,gsize,IPC_CREAT|IPC_EXCL|0666);
}

int getShm(key_t k,int size)
{
    return createShmHelper(key,gsize,IPC_CREAT);
}
    

 ②关联共享内存和进程

        在物理内存中创建好共享内存后,这个共享内存在创建的时候必须有权限才能进行操作。关联共享内存和进程,将共享内存的起始地址经过页表映射放到进程pcb中,具体挂接到pcb的哪里可以自己设定,设置为null让系统自主选择,即完成了关联。

char * attachShm(int shmid)
{
    char * start = (char *)shmat(shmid,nullptr,0);
    return start;
}

//2-3 进行通信

具体地通信可以自己设置

③取消关联进程和共享内存

detach(char * start)
{
    int n = shmdt(start);
    (void)n;
}

④删除共享内存

当运行两个端,发现进程退出后,再次运行无法创建共享内存,说明共享内存没有直接随着进程关闭。

关闭共享内存可以用两种方法

  1. ipcrm - m命令
  2. 函数shmctl
void delShm(int shmid)
{
   int n =  shmctl(shmid,IPC_RMID,nullptr);
   assert(n != -1);
   (void)n;
}

server.cc中主要实现创建共享内存,关联共享内存,进行通信(从共享内存读数据),取消关联,删除共享内存。

client.cc中主要实现获取共享内存,关联共享内存,进行通信(写数据到共享内存),取消关联。

接下来,优雅的修改上面的代码,封装起来。

common.hpp:

//前面的方法不变


#define SERVER 1
#define CLIENT 0

class Init
{

public:
    //构造
    Init(int t):type(t)
    {
        key_t k = getKey();
        if(type == SERVER) 
            shmid = createShm(k, gsize);
        else
             shmid = getShm(k, gsize);

        start = attachShm(shmid);
    }

    char *getStart()
    {     
        return start;
    }

    //析构
    ~Init()
    {
        detachShm(start);
        if(type == SERVER) delShm(shmid);
    }
private:
    char *start;
    int type;     //server or client
    int shmid;
};


server.cc

int main()
{
    Init init(SERVER);
    char * start = init.getStart();
    //开始通信
    ....
    //读取
    int n = 0;
    while(n <= 26)
    {
        cout<<" "<<start<<endl;  //设置start里都是字符串
        sleep(1);
    }

    //因为init是一个临时对象,所以函数跑完会自动调用析构
    return 0;
}

client.cc

int main()
{
    Init init(CLIENT);
    char * start = init.getStart();
    
    //开始通信

    ...
    //往start里写
    char c = 'A';
    while(c <= 'Z')
    {
        start[c-'A'] = c;
        c++;
        start[c] = '\0';
        sleep(1);
    }

    return 0;
}

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

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

相关文章

字节跳动岗位的薪酬体系曝光,看完感叹:真的不服不行

曾经的互联网是PC的时代&#xff0c;随着智能手机的普及&#xff0c;移动互联网开始飞速崛起。而字节跳动抓住了这波机遇&#xff0c;2015年&#xff0c;字节跳动全面加码短视频&#xff0c;从那以后&#xff0c;抖音成为了字节跳动用户、收入和估值的最大增长引擎。 自从字节…

Web3数据云OORT推出商用版智能代理构建平台:OORT TDS

随着技术进步和数据隐私问题的日益凸显&#xff0c;生成式AI和去中心化技术联手为企业和个人开辟了全新的互动视野。站在这一趋势的前沿&#xff0c;OORT展现了其在去中心化数据云领域的技术实力&#xff0c;作为行业的领先者&#xff0c;今日Oort正式宣布OORT TDS (Talk-to-Da…

MAGNA 直连 EDI 解决方案

全球首屈一指的汽车零部件供应商&#xff0c;在28个国家设有335家制造工厂&#xff0c;96个产品开发、工程和销售中心。产品主要包括制造车身、底盘、外饰、座椅、动力总成、电子、主动驾驶辅助、镜像、闭锁以及车顶系统&#xff0c;拥有多个领域的电子和软件工程能力。 MAGNA与…

row_number() over(partition by xx order by xx desc)

一、目的 主要用于根据某个字段对数据分组去重 二、demo 1. 有数据表 duplicate_test 如下 2. 使用 name 作为 key 对数据分组&#xff0c;并增加一列标识序号 idx&#xff08;根据 时间戳倒序标记序号&#xff09; select name,row_number() over(partition by name order…

IT6225B芯片方案|替代IT6225B方案|CS5366国产Typec转hdmi投屏方案

国产CS5366 透过模拟与数字的设计及28nm先进制程工艺,大幅降低功耗,无需增加散热片,提高产品可靠性,CS5366完全替代联阳IT6225B/IT6225,CS5366是一款Type-C转HDMI 2.0 4K60USB 3.0PD3.1/3.0高集成度视频转换芯片方案. 1.cs5366功耗低&#xff1a; CS5366系列符合USB电源传输规…

TCP数据报结构分析(面试重点)

在传输层中有UDP和TCP两个重要的协议&#xff0c;下面将针对TCP数据报的结构进行分析 关于UDP数据报的结构分析推荐看UDP数据报结构分析&#xff08;面试重点&#xff09; TCP结构图示 TCP报头结构的分析 一.16位源端口号 源端口表示发送数据时&#xff0c;发送方的端口号&am…

IO模型:阻塞和非阻塞

一、五种IO模型------读写外设数据的方式 阻塞: 不能操作就睡觉 非阻塞&#xff1a;不能操作就返回错误 多路复用&#xff1a;委托中介监控 信号驱动&#xff1a;让内核如果能操作时发信号&#xff0c;在信号处理函数中操作 异步IO&#xff1a;向内核注册操作请求&…

ES+Redis+MySQL,这个高可用架构设计太顶了!

目录 背景ES 高可用方案会员 Redis 缓存方案高可用会员主库方案异常会员关系治理展望&#xff1a;更精细化的流控和降级策略 背景 会员系统是一种基础系统&#xff0c;跟公司所有业务线的下单主流程密切相关。如果会员系统出故障&#xff0c;会导致用户无法下单&#xff0c;…

RS485隔离电路方案

RS485总线是一种使用平衡发送&#xff0c;差分接收实现通讯的通用串口通信总线&#xff0c;由于其具有抗共模干扰能力强、成本低、抗噪能力强、传输距离远、传输速率高、可连接多达256个收发器等优点&#xff0c;广泛应用于工业智能仪表&#xff0c;通讯设备等各个领域。 RS485…

Flutter:getX的学习

前言 学习教程&#xff1a;Getx教程_FlutterGetx系列实战教程 简介 getX是第三方的状态管理插件&#xff0c;不仅具有状态管理的功能&#xff0c;还具有路由管理、主题管理、国际化多语言管理、网络请求、数据验证等功能。相比其他状态管理组件&#xff0c;getX简单、功能强大…

JDK源码解析-Object

1. Object类 所有类的基类——java.lang.Object Object 类是所有类的基类&#xff0c;当一个类没有直接继承某个类时&#xff0c;默认继承Object类Object 类属于 java.lang 包&#xff0c;此包下的所有类在使用时无需手动导入&#xff0c;系统会在程序编译期间自动导入。 思…

(二)范数与距离

本文主要内容如下&#xff1a; 1. 范数的定义2. 常见的范数举例3. 范数的等价4. 距离与度量空间的定义 1. 范数的定义 定义1-1&#xff1a;设 E E E 为向量空间&#xff0c; R \mathbb{R} R 为实数域。若映射 ∥ ⋅ ∥ : E → R : x ↦ ∥ x ∥ \begin{equation*} \lVert\cd…

12.物联网LWIP之消息处理机制,lwip消息传递机制

一。LWIP数据包消息处理 1.接受数据包 2.构造消息 3.投递消息 4.获取消息 5.处理数据包 api_msg 这个结构体包括执行函数所必需的一切,对于另一个线程上下文中的netconn(主要用于处理netconn)在tcpip_thread上下文中(线程安全)。 struct api_msg { /* 大家可以理解为是一个so…

ssm学生信息管理系统源码和论文

ssm学生信息管理系统源码和论文075 开发工具&#xff1a;idea 数据库mysql5.7 数据库链接工具&#xff1a;navcat,小海豚等 技术&#xff1a;ssm 摘 要 传统办法管理学生信息首先需要花费的时间比较多&#xff0c;其次数据出错率比较高&#xff0c;而且对错误的数据进行…

多目标应用:基于多目标向日葵优化算法(MOSFO)的微电网多目标优化调度MATLAB

一、微网系统运行优化模型 参考文献&#xff1a; [1]李兴莘,张靖,何宇,等.基于改进粒子群算法的微电网多目标优化调度[J].电力科学与工程, 2021, 37(3):7 二、多目标向日葵优化算法 多目标向日葵优化算法&#xff08;Multi-objective sunflower optimization&#xff0c;MOS…

企业网络安全:威胁检测和响应 (TDR)

什么是威胁检测和响应 威胁检测和响应&#xff08;TDR&#xff09;是指识别和消除 IT 基础架构中存在的恶意威胁的过程。它涉及主动监控、分析和操作&#xff0c;以降低风险并防止未经授权的访问、恶意活动和数据泄露&#xff0c;以免它们对组织的网络造成任何潜在损害。威胁检…

新开通的抖店没有销量和体验分,如何找达人带货起店?教程如下

我是王路飞。 做抖店&#xff0c;想要快速起店&#xff0c;无非就是做动销&#xff0c;或者货损。 但是动销比较有风险&#xff0c;货损的话&#xff0c;一个是新手不会具体的操作和设置&#xff0c;一个是自己利润受损。 所以今天给你们说下&#xff0c;新开通的抖店在没有…

Java EE 突击 15 - Spring Boot 统一功能处理

Spring Boot 统一功能处理 一 . 统一功能的处理1.1 初级阶段 : 不断重复1.2 中级阶段 : 集成方法1.3 高级阶段 : Spring AOP1.4 超高级阶段 : Spring 拦截器准备工作实现拦截器自定义拦截器将自定义拦截器加入到系统配置 拦截器实现原理扩展 : 统一访问前缀添加 二 . 统一异常的…

机器学习的第一节基本概念的相关学习

目录 1.1 决策树的概念 1.2 KNN的概念 1.2.1KNN的基本原理 1.2.2 流程&#xff1a; 1.2.3 优缺点 1.3 深度学习 1.4 梯度下降 损失函数 1.5 特征与特征选择 特征选择的目的 1.6 python中dot函数总结 一维数组的点积&#xff1a; 二维数组&#xff08;矩阵&#xff09;的乘法&am…

结构体对齐原理及在STM32中的设计原则和实现

在嵌入式系统开发中&#xff0c;结构体作为一种常见的数据组织方式&#xff0c;在内存中的布局方式对于程序性能和内存占用具有重要影响。本文将深入探讨单片机C语言中的结构体对齐原理、重要性以及不同的对齐方式&#xff0c;并通过示例演示结构体对齐如何影响内存占用、访问性…