【lesson46】进程通信之system V(共享内存)

news2025/1/19 2:39:21

文章目录

  • 共享内存通信原理
  • 用共享内存通信
    • shmServer.cc
    • shmClient.cc
  • 完整通信代码
    • common.hpp
    • Log.hpp
    • shmServer.cc
    • shmClient.cc
    • 通信测试
  • 共享内存借助管道添加访问控制
    • common.hpp
    • shmServer.cc
    • shmClient.cc

共享内存通信原理

两个进程将一块system V的物理地址通过页表映射到自己的进程地址空间中。
在这里插入图片描述
具体点:
在这里插入图片描述
共享内存的建立
共享内存提供者是OS
那么OS要不要管理共享内存?
当然要—>先描述,再组织----->重新理解共享内存:
共享内存 = 共享内存块 + 共享内存的内核数据结构

用共享内存通信

创建两个文件:
shmServer.cc:读取数据
shmClient.cc:写入数据

shmServer.cc

1.创建key值
在这里插入图片描述
在这里插入图片描述
fotk参数:
pathname:随便写一个固定的路径,主要是为了生成唯一key值标识共享内存。
proj_id:也是随便写一个值,目的pathname一样。
在这里插入图片描述
2.创建共享内存
在这里插入图片描述
参数key:通过唯一key值创建内存并且共享内存以key编号
参数size:要申请的字节共享内存大小
参数shmflg
在这里插入图片描述
返回值
在这里插入图片描述
成功返回用户层用来唯一表示共享内存的shmid
在这里插入图片描述
3.挂接共享内存到进程地址空间的共享区
在这里插入图片描述
参数shmid:用户层共享内存的唯一标识
参数shmaddr
在这里插入图片描述
参数shmflg
在这里插入图片描述
返回值
在这里插入图片描述
在这里插入图片描述
4.通信逻辑之后实现,先把其它逻辑走通。
5.通信结束,共享内存去挂接
在这里插入图片描述
参数shmaddr:之前挂接的共享内存地址
返回值
在这里插入图片描述
在这里插入图片描述
6.删除共享内存
在这里插入图片描述
参数shmid:共享内存用户层编号
参数cmd
在这里插入图片描述
参数buf
在这里插入图片描述
返回值
在这里插入图片描述
在这里插入图片描述
通信逻辑的实现:
在这里插入图片描述
我们直接输出共享内存中的数据即可。

shmClient.cc

1.获取key值
在这里插入图片描述
2.获取共享内存
在这里插入图片描述
3.挂接共享内存到进程地址空间的共享区
在这里插入图片描述
4.开始通信,通信逻辑之后再实现
5.共享内存去挂接
在这里插入图片描述
这里不用删除共享空间,因为共享空间不是这个进程创建的。

通信逻辑
在这里插入图片描述
我们直接向共享内存写数据。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

完整通信代码

common.hpp

#pragma once
#include <iostream>
#include <string>
#include <cstring>
#include <cassert>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include "Log.hpp"

#define PATH_NAME "/home/xiaolin/"
#define PROJ_ID 0x66
#define SHM_SIZE 4096

Log.hpp

#pragma once

#include <iostream>
#include <ctime>

#define DEBUG 0
#define NOTICE 1
#define WARNING 2
#define ERROR 3

const std::string msg[] = {
    "DEBUGE",
    "NOTICE",
    "WARNING",
    "ERROR"};

std::ostream &Log(std::string message, int level)
{
    std::cout << "|" << (unsigned)time(nullptr) << "|" << msg[level] << "|" << message;
    return std::cout;
}

shmServer.cc

#include "common.hpp"

std::string TransToHex(key_t k)
{
    char buffer[32];
    snprintf(buffer, sizeof buffer, "0x%x", k);
    return buffer;
}

int main()
{
    // 1.创建key值
    key_t key = ftok(PATH_NAME, PROJ_ID);
    if (key == -1)
    {
        perror("ftok");
        exit(1);
    }
    Log("create key success", DEBUG) << " server key : " << TransToHex(key) << std::endl;
    //sleep(10);

    // 2.创建共享内存
    int shmid = shmget(key, SHM_SIZE, IPC_CREAT | IPC_EXCL | 0666);
    if (shmid == -1)
    {
        perror("shget");
        exit(2);
    }
    Log("create shm success", DEBUG) << " shm id : " << shmid << std::endl;
    //sleep(10);

    // 3.挂接共享内存的地址,到进程地址空间
    char *shmaddress = (char *)shmat(shmid, nullptr, 0);
    if (shmaddress == (char *)((void *)-1))
    {
        perror("shmat");
        exit(3);
    }
    Log("attach shm success", DEBUG) << " shm address : " << (int)*shmaddress << std::endl;
    //sleep(10);

    // 4.进行通信的逻辑
    //Server读取数据
    while(true)
    {
        printf("%s\n",shmaddress);
        if(strcmp(shmaddress,"quit") == 0)
        {
            break;
        }
        sleep(1);
    } 
    
    // 5.去挂接
    int shmdt_res = shmdt((void*)shmaddress);
    if(shmdt_res == -1)
    {
        perror("shmdt");
        exit(4);
    }
    Log("unattach shm success", DEBUG) << " shm res : " << shmdt_res << std::endl;
    //sleep(10);

    //6.删除共享内存,IPC_RMID表示即便是有进程和当下的shm挂接,依旧删除共享内存
    int shmctl_res = shmctl(shmid,IPC_RMID,nullptr);
    if(shmctl_res == -1)
    {
        perror("shmctl");
        exit(5);
    }
    Log("shmctl shm success", DEBUG) << " shmctl res : " << shmctl_res << std::endl;
    //sleep(10);

    return 0;
}

shmClient.cc

#include "common.hpp"
std::string TransToHex(key_t k)
{
    char buffer[32];
    snprintf(buffer, sizeof buffer, "0x%x", k);
    return buffer;
}

int main()
{
    // 1.获取key值
    key_t key = ftok(PATH_NAME, PROJ_ID);
    if (key == -1)
    {
        perror("ftok");
        exit(1);
    }
    Log("create key success", DEBUG) << " server key : " << TransToHex(key) << std::endl;
    //sleep(10);

    // 2.获取共享内存
    int shmid = shmget(key, SHM_SIZE, 0);
    if (shmid == -1)
    {
        perror("shget");
        exit(2);
    }
    Log("create shm success", DEBUG) << " shm id : " << shmid << std::endl;
    //sleep(10);

    // 3.挂接共享内存
    char *shmaddress = (char *)shmat(shmid, nullptr, 0);
    if (shmaddress == (char *)((void *)-1))
    {
        perror("shmat");
        exit(3);
    }
    Log("attach shm success", DEBUG) << " shm address : " << *shmaddress << std::endl;
    //sleep(10);

    // 4.通信逻辑
    // clinent写入数据
    char c = 'a';
    for (; c <= 'z'; c++)
    {
        snprintf(shmaddress, SHM_SIZE - 1,
                 "hello server, 我是其他进程,我的pid: %d, inc: %c\n",
                 getpid(), c);
        
        sleep(1);
    }

    snprintf(shmaddress,SHM_SIZE-1,"quit"); 

    // 5.去挂接
    int shmdt_res = shmdt((void *)shmaddress);
    if (shmdt_res == -1)
    {
        perror("shmdt");
        exit(4);
    }
    Log("unattach shm success", DEBUG) << " shm res : " << shmdt_res << std::endl;
    //sleep(10);
    return 0;
}

通信测试

在这里插入图片描述
我们可以看到server端在client还没有写入数据是就一直读取内容。
在client端运行起来后,也还在读取数据。
在这里插入图片描述
client端写入数据结束后,再写入quit指令,server端随之退出。
在这里插入图片描述
这里我们能看到system V缺乏访问控制。
那么我们能添加访问控制吗?可以

共享内存借助管道添加访问控制

common.hpp

#pragma once
#include <iostream>
#include <string>
#include <cstring>
#include <cassert>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include "Log.hpp"

#define PATH_NAME "/home/xiaolin/"
#define PROJ_ID 0x66
#define SHM_SIZE 4096
#define FIFO_NAME "./fifo"
#define MODE 0666
#define READ O_RDONLY
#define WRITE O_WRONLY

class Init
{
public:
    Init()
    {
        umask(0);
        int n = mkfifo(FIFO_NAME,MODE);
        if(n == -1)
        {
            perror("mkfifo");
        }
        Log("create fifo success",NOTICE) << "\n";
    }
    ~Init()
    {
        int n = unlink(FIFO_NAME);
        if(n == -1)
        {
            perror("unlink");
        }
        Log("unlink fifo success",NOTICE) << "\n";
    }
};


int OpenFifo(std::string pathname,int flages) 
{
    int fd = open(pathname.c_str(),flages);
    if(fd < 0)
    {
        perror("open");
    }

    return fd;
}

void Wait(int fd)//阻塞等待
{
    Log("等待中....", NOTICE) << "\n";
    uint32_t temp = 0;
    ssize_t n = read(fd,&temp,sizeof(temp));
    assert(n == sizeof(uint32_t));
}

void Signal(int fd)//唤醒
{
    uint32_t temp = 1;
    ssize_t n = write(fd,&temp,sizeof(temp));
    assert(n == sizeof(uint32_t));
    Log("唤醒中....", NOTICE) << "\n";
}

void CloseFifo(int fd) 
{
    close(fd);
}

shmServer.cc

#include "common.hpp"

// 对应的程序,在加载的时候,会自动构建全局变量,自动调用构造函数 -- 创建管道文件
// 程序退出的时候,全局变量会被析构,自动调用析构函数-----删除管道文件
Init init;

std::string TransToHex(key_t k)
{
    char buffer[32];
    snprintf(buffer, sizeof buffer, "0x%x", k);
    return buffer;
}

int main()
{
    // 1.创建key值
    key_t key = ftok(PATH_NAME, PROJ_ID);
    if (key == -1)
    {
        perror("ftok");
        exit(1);
    }
    Log("create key success", DEBUG) << " server key : " << TransToHex(key) << std::endl;
    //sleep(10);

    // 2.创建共享内存
    int shmid = shmget(key, SHM_SIZE, IPC_CREAT | IPC_EXCL | 0666);
    if (shmid == -1)
    {
        perror("shget");
        exit(2);
    }
    Log("create shm success", DEBUG) << " shm id : " << shmid << std::endl;
    //sleep(10);

    // 3.挂接共享内存的地址,到进程地址空间
    char *shmaddress = (char *)shmat(shmid, nullptr, 0);
    if (shmaddress == (char *)((void *)-1))
    {
        perror("shmat");
        exit(3);
    }
    Log("attach shm success", DEBUG) << " shm address : " << (int)*shmaddress << std::endl;
    //sleep(10);

    // 4.进行通信的逻辑
    //Server读取数据
    /* int fd = OpenFifo(FIFO_NAME,READ);
    while(true)
    {
        Wait(fd);
        printf("%s\n",shmaddress);
        if(strcmp(shmaddress,"quit") == 0)
        {
            break;
        }
        sleep(1);
    }

    CloseFifo(fd); */

    //shift alt a 注释指令
    while(true)
    {
        printf("%s\n",shmaddress);
        if(strcmp(shmaddress,"quit") == 0)
        {
            break;
        }
        sleep(1);
    }

    // 5.去挂接
    int shmdt_res = shmdt((void*)shmaddress);
    if(shmdt_res == -1)
    {
        perror("shmdt");
        exit(4);
    }
    Log("unattach shm success", DEBUG) << " shm res : " << shmdt_res << std::endl;
    //sleep(10);

    //6.删除共享内存,IPC_RMID表示即便是有进程和当下的shm挂接,依旧删除共享内存
    int shmctl_res = shmctl(shmid,IPC_RMID,nullptr);
    if(shmctl_res == -1)
    {
        perror("shmctl");
        exit(5);
    }
    Log("shmctl shm success", DEBUG) << " shmctl res : " << shmctl_res << std::endl;
    //sleep(10);

    return 0;
}

shmClient.cc

#include "common.hpp"
std::string TransToHex(key_t k)
{
    char buffer[32];
    snprintf(buffer, sizeof buffer, "0x%x", k);
    return buffer;
}

int main()
{
    // 1.获取key值
    key_t key = ftok(PATH_NAME, PROJ_ID);
    if (key == -1)
    {
        perror("ftok");
        exit(1);
    }
    Log("create key success", DEBUG) << " server key : " << TransToHex(key) << std::endl;
    //sleep(10);

    // 2.获取共享内存
    int shmid = shmget(key, SHM_SIZE, 0);
    if (shmid == -1)
    {
        perror("shget");
        exit(2);
    }
    Log("create shm success", DEBUG) << " shm id : " << shmid << std::endl;
    //sleep(10);

    // 3.挂接共享内存
    char *shmaddress = (char *)shmat(shmid, nullptr, 0);
    if (shmaddress == (char *)((void *)-1))
    {
        perror("shmat");
        exit(3);
    }
    Log("attach shm success", DEBUG) << " shm address : " << *shmaddress << std::endl;
    //sleep(10);

    // 4.通信逻辑
    // clinent写入数据
    /* int fd = OpenFifo(FIFO_NAME,WRITE);
    while(true)
    {
        ssize_t n = read(0,shmaddress,SHM_SIZE-1);
        if(n > 0)
        {
            shmaddress[n-1] = 0;
            Signal(fd);
            if(strcmp(shmaddress,"quit") == 0)
            {
                break;
            }
            
        }
        else if(n == 0)
        {
            break;
        }
        else
        {
            perror("read");
        }
    }

    CloseFifo(fd); */
    
    char c = 'a';
    for (; c <= 'z'; c++)
    {
        snprintf(shmaddress, SHM_SIZE - 1,
                 "hello server, 我是其他进程,我的pid: %d, inc: %c\n",
                 getpid(), c);
        
        sleep(1);
    }

    snprintf(shmaddress,SHM_SIZE-1,"quit");

    // 5.去挂接
    int shmdt_res = shmdt((void *)shmaddress);
    if (shmdt_res == -1)
    {
        perror("shmdt");
        exit(4);
    }
    Log("unattach shm success", DEBUG) << " shm res : " << shmdt_res << std::endl;
    //sleep(10);
    return 0;
}

Log.hpp和之前一样,这里就不再写一遍。

附加:
Linux下查看共享内存:

ipcs -m

Linux下手动删除共享内存:

ipcrm -m(shimd)

Linux下循环查看共享内存脚本:

while :; do ipcs -m; sleep 1; done

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

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

相关文章

JSP编程

JSP编程 您需要理解在JSP API的类和接口中定义的用于创建JSP应用程序的各种方法的用法。此外,还要了解各种JSP组件,如在前一部分中学习的JSP动作、JSP指令及JSP脚本。JSP API中定义的类提供了可借助隐式对象通过JSP页面访问的方法。 1. JSP API的类 JSP API是一个可用于创建…

大模型学习 一

https://www.bilibili.com/video/BV1Kz4y1x7AK/?spm_id_from333.337.search-card.all.click GPU 计算单元多 并行计算能力强 指数更重要 A100 80G V100 A100 海外 100元/时 单卡 多卡并行&#xff1a; 单机多卡 模型并行 有资源的浪费 反向传播 反向传播&#xff08;B…

第6章 智能租房——前期准备

学习目标 了解智能租房项目&#xff0c;能够说出项目中各模块包含的功能 熟悉智能租房项目的开发模式与运行机制&#xff0c;能够复述项目的开发模式与运行机制 掌握智能租房项目的创建&#xff0c;能够独立创建智能租房项目 掌握智能租房项目的配置&#xff0c;能够为智能租…

教师考试,搜题软件哪个好用?大学生必备工具:搜题软件推荐 #微信#学习方法

在大学生的学习过程中&#xff0c;我们经常会遇到各种难题和疑惑。有时候&#xff0c;我们可能会花费大量的时间和精力去寻找答案&#xff0c;但结果却并不尽如人意。为了帮助大家更好地解决这个问题&#xff0c;今天我要向大家介绍几款备受大学生欢迎的搜题软件&#xff0c;它…

【NICN】探索牛客之求阶乘

1.题目描述 递归和非递归分别实现求n的阶乘&#xff08;不考虑溢出的问题&#xff09; 2.代码解题 2.1递归 递归思想&#xff1a; Fac(N) 1*2*3*……*N递归方式实现&#xff1a;1 N < 1 Fac(N)Fac(N-1)*N N > 2 long long Fac(int N) {if(N < 1)return 1;retu…

欢度春节,祝福万家。

值此春节佳节来临之际,新年问候如一道灯光&#xff0c;照亮我们前行的路。在这光芒中&#xff0c;期待与你携手走过新的一年。 春节是中华民族最重要的传统节日,它代表着新的开始和希望。在这个特殊的时刻,让我们放下过去的烦恼和忧虑,迎接新的挑战和机遇。让我们珍惜和家人团…

使用 Elasticsearch 和 OpenAI 构建生成式 AI 应用程序

本笔记本演示了如何&#xff1a; 将 OpenAI Wikipedia 向量数据集索引到 Elasticsearch 中使用 Streamlit 构建一个简单的 Gen AI 应用程序&#xff0c;该应用程序使用 Elasticsearch 检索上下文并使用 OpenAI 制定答案 安装 安装 Elasticsearch 及 Kibana 如果你还没有安装好…

Android性能调优 - 应用安全问题

Android应用安全 1.组件暴露&#xff1a; 像比如ContentProvider,BroadcastReceiver&#xff0c;Activity等组件有android:exported属性&#xff1b; 如果是私有组件 android:exported “false”&#xff1b; 如果是公有组件 android:exported “true” 且进行权限控制&…

Linux 存储管理(磁盘管理、逻辑卷LVM、交换分区swap)

目录 1.磁盘管理 1.1 磁盘简介 1.2 管理磁盘 添加磁盘 管理磁盘流程三步曲 1.查看磁盘信息 2.创建分区 3.创建文件系统 4.挂载mount 5.查看挂载信息 6.MBR扩展分区 7.重启后的影响 2.逻辑卷LVM 2.1 简介 ​​​​​​2.2 创建LVM 2.3 VG管理 2.4 LV管理实战-在…

单片机学习笔记---DS1302实时时钟工作原理

目录 DS1302介绍 学会读芯片手册&#xff08;DS1302芯片手册&#xff09; 封装 引脚定义 电源部分 时钟部分 通信部分 总结列表 内部结构图 电源控制部分 时钟控制部分 寄存器部分 访问部分 寄存器部分的详细定义 命令字 时序的定义 单字节读 单字节写 提前预…

qt/c++实现拓扑排序可视化

&#x1f482; 个人主页:pp不会算法^ v ^ &#x1f91f; 版权: 本文由【pp不会算法v】原创、在CSDN首发、需要转载请联系博主 &#x1f4ac; 如果文章对你有帮助、欢迎关注、点赞、收藏(一键三连)和订阅专栏哦 实现功能 1、选择文件导入初始数据 2、逐步演示 3、排序完成输出…

L1-096 谁管谁叫爹

一、题目 二、解题思路 依据题意判断即可。 三、代码 #include<iostream> using namespace std; #include<cmath> int main() {int n;cin>>n;while(n--){int n1,n2,s10,s20;cin>>n1>>n2;for(int i1;n1/i>0;i*10){s1(n1/i%10);}for(int i1;n…

FastDFS安装并整合Openresty

FastDFS安装 一、环境--centos7二、FastDFS--tracker安装2.1.下载2.2.FastDFS安装环境2.3.安装FastDFS依赖libevent库2.4.安装libfastcommon2.5.安装 libserverframe 网络框架2.6.tracker编译安装2.7.文件安装位置介绍2.8.错误处理2.9.配置FastDFS跟踪器(Tracker)2.10.启动2.11…

【JAVA WEB】 css背景属性 圆角矩形的绘制

目录 背景属性设置 圆角矩形 背景属性设置 背景颜色,在style中 background-color:颜色&#xff1b; 背景图片 background-image:url(……) 背景图片的平铺方式 background-repeat: 平铺方式 repeat 平铺&#xff08;默认&#xff09;no-repeat 不平铺repeat-x 水平平铺repea…

设计模式3-责任链模式

责任链模式是一种行为设计模式&#xff0c;它允许你创建一个对象链。请求沿着这条链传递&#xff0c;直到有一个对象处理它为止。这种模式通常用于需要以某种方式动态地决定处理请求的顺序或方式的情况。 类图&#xff1a; 从图中可见最大的特点是AbstractHandler它自己聚合了自…

探索Xposed框架:个性定制你的Android体验

探索Xposed框架&#xff1a;个性定制你的Android体验 1. 引言 在当今移动设备市场中&#xff0c;Android系统作为最受欢迎的操作系统之一&#xff0c;其开放性和可定制性备受用户青睐。用户希望能够根据个人喜好和需求对其设备进行定制&#xff0c;以获得更符合自己习惯的使用…

svg 进阶

svg 进阶 svg 应用场景 绘制 icon绘制动画 svg viewport 和 viewBox viewport 是 svg 图像的可见区域 viewBox 是用于在画布上绘制 svg 图形的坐标系统 在一下案例中 svg中 width“500” height“200” 就是可视区域 比如你的svg是100X100但是你的可视区域只有20X20 那么他…

c语言中的模拟多态性

在C语言中模拟多态性 多态性是面向对象编程中的一个核心概念&#xff0c;它允许我们通过一个共同的接口来操作不同的数据类型。虽然C语言是一种过程式语言&#xff0c;本身不直接支持面向对象的特性&#xff0c;如继承、封装和多态&#xff0c;但我们可以通过一些技巧来模拟这些…

mac docker 宿主机和容器间网络打通

动因 是这样&#xff0c;笔者最近满怀欣喜入手Docker&#xff0c;看着各种文章命令都是不断点头称道&#xff1a;“嗯嗯&#xff0c;不错不错”,在接下来终于准备大干一场的时候碰壁了&#xff0c;主要情况是说在Mac中跑了第一把的时候发现碰到&#xff0c;虚拟机和宿主机居然…

arkTS开发鸿蒙OS应用(登录页面实现,连接数据库)

前言 喜欢的朋友可在抖音、小红书、微信公众号、哔哩哔哩搜索“淼学派对”。知乎搜索“编程淼”。 前端架构 Toubu.ets import router from ohos.router Component export struct Header{build(){// 标题部分Row({space:5}){Image($r(app.media.fanhui)).width(20).onClic…