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


    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

    在这里插入图片描述

    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);  
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    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);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

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

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

    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);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    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;          // 三者进行或运算
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

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

    4. 本项目共享内存的设计与实现

    4.1 设计思路

    • shm
      在这里插入图片描述

    • 秘钥协商服务器和协商客户端部署在同一台主机?
      - 实际的应用场景是部署在不同的主机上

    • 场景:

    • 服务器端发送消息 -> 传智共屏软件 -> 服务器 -> 独立进程
      • 加密使用对称加密的秘钥
      • 部署秘钥协商的服务器端程序
        • 独立进程
      • 最终的需求:
        • 秘钥协商生成的秘钥给到传智共屏服务器
          • 这两个进程没关系 -> 没有血缘关系
          • 效率最高: 共享内存(shm)
    • 客户端接收消息 -> 传智共屏软件 -> 客户端 -> 独立进程
      • 解密, 使用对称加密的秘钥
      • 部署秘钥协商的客户端程序
        • 独立进程
      • 最终的需求:
        • 秘钥协商生成的秘钥给到传智共屏客户端
          • 这两个进程没关系 -> 没有血缘关系
          • 效率最高: 共享内存(shm)
    • 服务器和客户端共享内存中的秘钥个数?

      • 服务器端:
        • 秘钥多个, 应服务器需要和多客户端连接
          • 每个客户端对应一个加密的秘钥, 这些秘钥都是不同的
      • 客户端:
        • 需要秘钥1个
          • 一个客户端只需要和一个服务器进行连接

    4.2 共享内存中存储的秘钥信息都有什么?

    struct SecKeyInfo
    {
        // 初始化
        SecKeyInfo()
        {
            key = string();
            clientID = string();
          ...
            status  = true;
        }
        // 对称加密的秘钥
        string key;
        // 如果鉴别这个秘钥属于谁 -> 查询秘钥的时候根据clientID和serverID进行查询
        string clientID;
        string serverID;
        // 可选 -> 秘钥编号ID
        int seckeyID;
        // 可选 -> 秘钥状态
        bool status;    // true:可用, false:不可用
    }
    
    SecKeyInfo info;
    memset(&info, 0, sizeof(info));    // error, 成员是string不能做memset操作
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    4.3 共享内存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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    在这里插入图片描述

    4.4 共享内存的创建和使用-客户端为例

    具体代码请查看代码仓库
    在这里插入图片描述

    class BaseShm
    {
    public:
    	// 通过key打开共享内存
    	BaseShm(int key);
    	// 通过传递进来的key创建/打开共享内存
    	BaseShm(int key, int size);
    	// 通过路径打开共享内存
    	BaseShm(string name);
    	// 通过路径创建/打开共享内存
    	BaseShm(string name, int size);
    
    	void* mapShm();
    	int unmapShm();
    	int delShm();
    
    	~BaseShm();
    
    private:
    	int getShmID(key_t key, int shmSize, int flag);
    
    private:
    	int m_shmID;
    protected:
    	void* m_shmAddr = NULL;
    };
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    const char RandX = 'x';
    BaseShm::BaseShm(int key)
    {
    	getShmID(key, 0, 0);
    }
    
    BaseShm::BaseShm(int key, int size)
    {
    	getShmID(key, size, IPC_CREAT | 0664);
    }
    
    BaseShm::BaseShm(string name)
    {
    	key_t key = ftok(name.data(), RandX);
    	getShmID(key, 0, 0);
    }
    
    BaseShm::BaseShm(string name, int size)
    {
    	key_t key = ftok(name.data(), RandX);
    	// 创建共享内存
    	getShmID(key, size, IPC_CREAT | 0664);
    }
    
    void * BaseShm::mapShm()
    {
    	// 关联当前进程和共享内存
    	m_shmAddr = shmat(m_shmID, NULL, 0);
    	if (m_shmAddr == (void*)-1)
    	{
    		return NULL;
    	}
    	return m_shmAddr;
    }
    
    int BaseShm::unmapShm()
    {
    	int ret = shmdt(m_shmAddr);
    	return ret;
    }
    
    int BaseShm::delShm()
    {
    	int ret = shmctl(m_shmID, IPC_RMID, NULL);
    	return ret;
    }
    
    BaseShm::~BaseShm()
    {
    }
    
    int BaseShm::getShmID(key_t key, int shmSize, int flag)
    {
    	cout << "share memory size: " << shmSize << endl;
    	m_shmID = shmget(key, shmSize, flag);
    	if (m_shmID == -1)
    	{
    		// 写log日志
    		cout << "shmget 失败" << endl;
    	}
    	return m_shmID;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    
    class NodeSecKeyInfo
    {
    public:
    	NodeSecKeyInfo() : status(0), seckeyID(0)
    	{
    		bzero(clientID, sizeof(clientID));
    		bzero(serverID, sizeof(serverID));
    		bzero(seckey, sizeof(seckey));
    	}
    	int status;		// 秘钥状态: 1可用, 0:不可用
    	int seckeyID;	// 秘钥的编号
    	char clientID[12];	// 客户端ID, 客户端的标识
    	char serverID[12];	// 服务器ID, 服务器标识
    	char seckey[128];	// 对称加密的秘钥
    };
    
    class SecKeyShm : public BaseShm
    {
    public:
    	// 打开或创建一块共享内存
    	// 这个操作是在父类中做的
    	SecKeyShm(int key, int maxNode);
    
    	//maxNode节点的个数,即存储多少个秘钥,存储结构体NodeSecKeyInfo的个数
    	SecKeyShm(string pathName, int maxNode);
    	~SecKeyShm();
    
    	void shmInit();
    	int shmWrite(NodeSecKeyInfo* pNodeInfo);
    	NodeSecKeyInfo shmRead(string clientID, string serverID);
    
    private:
    	int m_maxNode;
    };
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    
    SecKeyShm::SecKeyShm(int key, int maxNode)
    	: BaseShm(key, maxNode * sizeof(NodeSecKeyInfo))
    	, m_maxNode(maxNode)
    {
    }
    
    SecKeyShm::SecKeyShm(string pathName, int maxNode)
    	: BaseShm(pathName, maxNode * sizeof(NodeSecKeyInfo))
    	, m_maxNode(maxNode)
    {
    }
    
    SecKeyShm::~SecKeyShm()
    {
    }
    
    void SecKeyShm::shmInit()
    {
    	//m_shmAddr在BaseShm.cpp中,是关联当前进程和共享内存时拿到的共享内存的起始地址
    	if (m_shmAddr != NULL)
    	{                                             //共享内存的大小--->参数三:节点个数*节点大小
    		memset(m_shmAddr, 0, m_maxNode * sizeof(NodeSecKeyInfo));
    	}
    }
    
    int SecKeyShm::shmWrite(NodeSecKeyInfo * pNodeInfo)
    {
    	int ret = -1;
    	// 关联共享内存
    	NodeSecKeyInfo* pAddr = static_cast<NodeSecKeyInfo*>(mapShm());
    	if (pAddr == NULL)
    	{
    		return ret;
    	}
    
    	// 判断传入的网点密钥是否已经存在
    	NodeSecKeyInfo	*pNode = NULL;
    	for (int i = 0; i < m_maxNode; i++)
    	{
    		// pNode依次指向每个节点的首地址
    		pNode = pAddr + i;
    		cout << i << endl;
    		cout << "clientID 比较: " << pNode->clientID << ", " << pNodeInfo->clientID << endl;
    		cout << "serverID 比较: " << pNode->serverID << ", " << pNodeInfo->serverID << endl;
    		cout << endl;
    		if (strcmp(pNode->clientID, pNodeInfo->clientID) == 0 &&
    			strcmp(pNode->serverID, pNodeInfo->serverID) == 0)
    		{
    			// 如果找到了该网点秘钥已经存在, 使用新秘钥覆盖旧的值
    			memcpy(pNode, pNodeInfo, sizeof(NodeSecKeyInfo));
    			unmapShm();
    			cout << "写数据成功: 原数据被覆盖!" << endl;
    			return 0;
    		}
    	}
    
    	// 若没有找到对应的信息, 找一个空节点将秘钥信息写入
    	int i = 0;
    	NodeSecKeyInfo tmpNodeInfo; //空结点
    	for (i = 0; i < m_maxNode; i++)
    	{
    		pNode = pAddr + i;
    		if (memcmp(&tmpNodeInfo, pNode, sizeof(NodeSecKeyInfo)) == 0)
    		{
    			ret = 0;
    			memcpy(pNode, pNodeInfo, sizeof(NodeSecKeyInfo));
    			cout << "写数据成功: 在新的节点上添加数据!" << endl;
    			break;
    		}
    	}
    	if (i == m_maxNode)
    	{
    		ret = -1;
    	}
    
    	unmapShm();
    	return ret;
    }
    
    NodeSecKeyInfo SecKeyShm::shmRead(string clientID, string serverID)
    {
    	int ret = 0;
    	// 关联共享内存
    	NodeSecKeyInfo *pAddr = NULL;
    	pAddr = static_cast<NodeSecKeyInfo*>(mapShm());
    	if (pAddr == NULL)
    	{
    		cout << "共享内存关联失败..." << endl;
    		return NodeSecKeyInfo();
    	}
    	cout << "共享内存关联成功..." << endl;
    
    	//遍历网点信息
    	int i = 0;
    	NodeSecKeyInfo info;
    	NodeSecKeyInfo	*pNode = NULL;
    	// 通过clientID和serverID查找节点
    	cout << "maxNode: " << m_maxNode << endl;
    	for (i = 0; i < m_maxNode; i++)
    	{
    		pNode = pAddr + i;
    		cout << i << endl;
    		cout << "clientID 比较: " << pNode->clientID << ", " << clientID.data() << endl;
    		cout << "serverID 比较: " << pNode->serverID << ", " << serverID.data() << endl;
    		if (strcmp(pNode->clientID, clientID.data()) == 0 &&
    			strcmp(pNode->serverID, serverID.data()) == 0)
    		{
    			// 找到的节点信息, 拷贝到传出参数
    			info = *pNode;
    			cout << "++++++++++++++" << endl;
    			cout << info.clientID << " , " << info.serverID << ", "
    				<< info.seckeyID << ", " << info.status << ", "
    				<< info.seckey << endl;
    			cout << "===============" << endl;
    			break;
    		}
    	}
    
    	unmapShm();
    	return info;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    ClientOP::ClientOP(string jsonFile)
    {
    	// 解析json文件, 读文件 -> Value
    	ifstream ifs(jsonFile);
    	Reader r;
    	Value root;
    	r.parse(ifs, root);
    	// 将root中的键值对value值取出
    	m_info.ServerID = root["ServerID"].asString();
    	m_info.ClientID = root["ClientID"].asString();
    	m_info.ip = root["ServerIP"].asString();
    	m_info.port = root["Port"].asInt();
    
    	// 实例化共享内存对象
    	// 从配置文件中读 key/pathname
    	string shmKey = root["ShmKey"].asString();
    	int maxNode = root["ShmMaxNode"].asInt();
    	// 客户端存储的秘钥只有一个
    	m_shm = new SecKeyShm(shmKey, maxNode);
    }
    
    ClientOP::~ClientOP()
    {
    	delete m_shm;
    }
    
    
    	
    	// 秘钥写入共享内存中
    	NodeSecKeyInfo info;
    	strcpy(info.clientID, m_info.ClientID.data());
    	strcpy(info.serverID, m_info.ServerID.data());
    	strcpy(info.seckey, key.data());
    	info.seckeyID = resData->seckeyid();
    	info.status = true;
    	m_shm->shmWrite(&info);
    
    	delete factory;
    	delete c;
    	// 这是一个短连接, 通信完成, 断开连接
    	tcp->disConnect();
    	delete tcp;
    
    	return true;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    4.5 共享内存的创建和使用-服务端

    // 处理客户端请求
    class ServerOP
    {
    public:
    	enum KeyLen {Len16=16, Len24=24, Len32=32};
    	ServerOP(string json);
    	void startServer();
    	static void* working(void* arg);
    	friend void* workHard(void* arg);
    	string seckeyAgree(RequestMsg* reqMsg);
    	~ServerOP();
    
    private:
    	string getRandKey(KeyLen len);
    
    private:
    	string m_serverID;	// 当前服务器的ID
    	string m_dbUser;
    	string m_dbPwd;
    	string m_dbConnStr;
    	unsigned short m_port;
    	map<pthread_t, TcpSocket*> m_list;
    	TcpServer *m_server = NULL;
    	OCCIOP m_occi;
    // 创建共享内存对象
    	SecKeyShm* m_shm;
    };
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    ServerOP::ServerOP(string json)
    {
    	// 解析json文件, 读文件 -> Value
    	ifstream ifs(json);
    	Reader r;
    	Value root;
    	r.parse(ifs, root);
    	// 将root中的键值对value值取出
    	m_port = root["Port"].asInt();
    	m_serverID = root["ServerID"].asString();
    	// 数据库相关的信息
    	m_dbUser = root["UserDB"].asString();
    	m_dbPwd = root["PwdDB"].asString();
    	m_dbConnStr = root["ConnStrDB"].asString();
    
    	// 实例化一个连接oracle数据的对象
    	m_occi.connectDB(m_dbUser, m_dbPwd, m_dbConnStr);
    
    	// 实例化共享内存对象
    	// 从配置文件中读 key/pathname
    	string shmKey = root["ShmKey"].asString();
    	int maxNode = root["ShmMaxNode"].asInt();
    	// 客户端存储的秘钥只有一个
    	m_shm = new SecKeyShm(shmKey, maxNode);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    // 将生成的新秘钥写入到数据库中 -> 操作 SECKEYINFO
    NodeSecKeyInfo node;
    strcpy(node.clientID, reqMsg->clientid().data());
    strcpy(node.serverID, reqMsg->serverid().data());
    strcpy(node.seckey, key.data());
    node.seckeyID = m_occi.getKeyID();	// 秘钥的ID
    info.seckeyID = node.seckeyID;
    node.status = 1;
    // 初始化node变量
    bool bl = m_occi.writeSecKey(&node);
    if(bl)
    {
    	// 成功
    	m_occi.updataKeyID(node.seckeyID + 1);
    	// 写共享内存
    	m_shm->shmWrite(&node);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    4.6 客户端和服务端内存位置

    因为客户端和服务端在不同的主机上,所以可以指向不同的内存。

    在这里插入图片描述

  • 相关阅读:
    Springboot毕设项目个性化健康饮食推荐平台79no0(java+VUE+Mybatis+Maven+Mysql)
    物联网开发笔记(48)- 使用Micropython开发ESP32开发板之控制OLED ssd1306屏幕
    北大数学天才“韦神”上热搜,随手帮6个博士解决困扰4个月的难题
    侦听器&&模板引用&&组件注册&&组件之间的数据传递
    即拼七人团增加消费者复购欲望,为企业赋能
    力扣:143. 重排链表(Python3)
    2023亚太杯数学建模思路 - 案例:FPTree-频繁模式树算法
    LeetCode 454 四数相加II 383. 赎金信 15. 三数之和 18. 四数之和
    crontab定时任务是否执行
    Java——正则表达式
  • 原文地址:https://blog.csdn.net/jiangchufeng123/article/details/133980996