Openssl数据安全传输平台007:共享内存及代码的实现 ——待完善项目具体代码和逻辑

文章目录

  • 0. 代码仓库
  • 1. 使用流程
    • 案例代码:
  • 2. API解析
    • 2.1 创建或打开一块共享内存区
    • 2.2 将当前进程和共享内存关联到一起
    • 2.3 将共享内存和当前进程分离
    • 2.4 共享内存操作 -( 删除共享内存 )
  • 3. 思考问题
  • 3. ftok函数
  • 4. 共享内存API封装-以本项目为例

0. 代码仓库

https://github.com/Chufeng-Jiang/OpenSSL_Secure_Data_Transmission_Platform

1. 使用流程

  1. 向内核申请一块内存 -> 指定大小
  2. 如果有两个进程, 需要通信, 可以使用这块共享内存来完成, 先创建出这两个进程
    • 进程A
    • 进程B
  3. 进程A和进程B分别和共享内存进行关联
    • 拿到共享内存的地址 -> 首地址
  4. 两个进程可以通过这个首地址对共享内存进行读/写操作
  5. 如果这个进程不再使用这块共享内存, 需要和共享内存断开关联
    • 进程退出, 对共享内存是没有任何影响的
  6. 当不再使用共享内存的时候, 需要将共享内存销毁

案例代码:

https://github.com/Chufeng-Jiang/Linux-System-Programming/tree/main/0110%20Shared%20Memory

Openssl数据安全传输平台007:共享内存及代码的实现 ——待完善项目具体代码和逻辑_第1张图片

2. API解析

2.1 创建或打开一块共享内存区

// 创建共享内存
// 共享内存已经存在, 打开共享内存
// 可以创建多块共享内存

int shmget(key_t key, size_t size, int shmflg);
    参数:
        - key: 通过这个key记录共享内存在内核中的位置, 需要是一个>0的整数, ==0不行
            随便指定一个数就可以, 后边会介绍一个函数ftok
        - size: 创建共享内存的时候, 指定共享内存的大小
            - 如果是打开一个已经存在的共享内存, size写0就可以
        - shmflg: 创建共享内存的时候使用, 类似于open函数的flag
            - IPC_CREAT: 创建共享内存
                - 创建的时候需要给共享内存一个操作权限
                    - IPC_CREAT | 0664
            - IPC_CREAT | IPC_EXCL: 检测共享内存是否存在
                - 如果存在函数返回-1
                - 不存在, 返回0
    返回值:
        成功: 创建/打开成功, 得到一个整形数 -> 对应这块共享内存
        失败: -1

// 应用
// 1. 创建共享内存
int shmid = shmget(100, 4096,  IPC_CREAT | 0664);
int shmid = shmget(200, 4096,  IPC_CREAT | 0664);
// 2. 打开共享内存
int shmid = shmget(100, 0, 0);  

2.2 将当前进程和共享内存关联到一起

// 进程和共享内存产生关系
void *shmat(int shmid, const void *shmaddr, int shmflg);
    参数:
        - shmid: 通过这个参数访问共享内存, shmget()函数的返回值
        - shmaddr: 指定共享内存在内核中的位置, 写NULL -> 委托内核区指定
        - shmflg: 关联成功之后对共享内存的操作权限
            - SHM_RDONLY: 只读
            - 0: 读写
    返回值:
        成功: 共享内存的地址 (起始地址)
        失败:  (void *) -1
        
// 函数调用:
void* ptr = shmat(shmid, NULL, 0);
// 写内存
memcpy(ptr, "xxxx", len);
// 读内存
printf("%s", (char*)prt);

2.3 将共享内存和当前进程分离

// 进程和共享内存分离 -> 二者就没有关系了
int shmdt(const void *shmaddr);
    参数: 共享内存的起始地址, shmat()返回值
    返回值:
        - 成功: 0
        - 失败: -1

2.4 共享内存操作 -( 删除共享内存 )

// fcntl
// setsockopt
// getsockopt
// 对共享内存进程操作
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
    参数: 
        - shmid: 通过这个参数访问共享内存, shmget()函数的返回值
        - cmd: 对共享内存的操作
            - IPC_STAT: 获取共享内存的状态
            - IPC_SET: 设置共享内存状态
            - IPC_RMID: 标记共享内存要被销毁
        - buf: 为第二个参数服务的
            cmd==IPC_STAT: 获取共享内存具体状态信息
            cmd==IPC_SET: 自定义共享内存状态, 设置到内核的共享内存中
            cmd==IPC_RMID: 这个参数没有用了, 指定为NULL
    返回值:
        成功: 0
        失败: -1
        
// 删除共享内存
shmctl(shmid, IPC_RMID, NULL);

3. 思考问题

  • 问题1: 操作系统如何知道一块共享内存被多少进程关联?

    • 共享内存维护了一个结构体struct shmid_ds这个结构体中有一个成员shm_nattch
    • shm_nattch中记录了关联的进程的个数
  • 问题2: 是不是可以对共享内存进行多次删除 -> 多次调用shmctl

    • 可以多次操作
  • 因为shmctl函数是标记删除共享内存, 部署直接删除

    • 什么时候被真正删除了?
    • 当关联这块共享内存进程个数 == 0 的时候, 真正被删除了
      • shm_nattch== 0

3. ftok函数

ftok函数是IPC中常用的一个函数,它是由Unix系统提供的一个应用程序编程接口(API)。它的作用是根据一个指定的文件名和一个整数,生成一个不重复的键值(key)。

key_t ftok(const char *pathname, int proj_id);

首先根据一个任意存在的pathname绝对路径提取其所属文件系统的特有信息,包括设备号(stat.st_dev)和inode号(stat.st_ino),其获取方法参见上述程序中的sata结构,然后再结合ftok()函数的proj_id参数,按照如下规则计算key:

key1 = stat.st_ino & 0xffff;   // 保留低16位
key2 = stat.st_dev & 0xff;     // 保留低8位
key2 << = 16;                  // 左移16位
key3 = proj_id & 0xff;         // 保留低8位
key3 << = 24;                  // 左移24位
key = key1|key2|key3;          // 三者进行或运算

本例中,pathname=’/tmp‘,ftok()函数提取的设备号为0x804,inode号为0x280001,proj_id为0x01,根据以上运算过程,key1=0x01,key2=0x40000,key3=0x1000000,三者求或得到key=0x1040001,与程序输出的结果一致。

4. 共享内存API封装-以本项目为例

//shmget
int shmget(key_t key, size_t size, int shmflg);
class BaseShm
{
public:
    BaseShm(int key);    // 根据key打开共享内存
    BaseShm(string path);    // 根据string path-> int key 打开共享内存
    BaseShm(int key, int size);    // 根据key创建共享内存
    BaseShm(string path, int size);    // 根据string path-> int key 创建共享内存

    void* mapshm()
    {
        m_ptr = shmat(shmid);
        return m_ptr;
    }
    int unmapshm()
    {
           shmdt(m_ptr);
    }
    int delshm()
    {
        shmctl(shmid);
    }

private:
    int m_shmid;    // shmget返回值
    void* m_ptr;
}

Openssl数据安全传输平台007:共享内存及代码的实现 ——待完善项目具体代码和逻辑_第2张图片

你可能感兴趣的:(数据安全传输基础设置平台项目,共享内存)