C++ - 多个buffer合并成一个buffer的管理类

博客介绍了用C++实现的将多个buffer合并成一个buffer的管理类。客户端向服务端提交多buffer信息较麻烦,该管理类可将多个buffer封装成一个,只需提交一次。还能从大buffer中提取小buffer信息。此外,提到对提交内容加密的两种方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

C++ - 多个buffer合并成一个buffer的管理类

概述

客户端要向服务端提交包含在多个buffer中的信息, 如果提交多个buffer(文件), 挺麻烦的.
如果将这些buffer(文件), 压缩成一个文件, 处理起来也不是很方便.

尝试将多个buffer封装到一个buffer中, 最终将封装好的buffer(写成文件也行)给服务端, 只需要提交一次.
封装了一个管理类, 可以向管理类push多个buffer, 最后调用接口, 得到一个完整的大buffer(包含所有压入的小buffer).
对提取的大buffer, 使用者的程序, 再调用分析接口, 可以取得调用者压入的多个小buffer的具体信息.

笔记

运行效果

	header info :
	name = myapp_cfg
	buffer total len = 265
	buffer block cnt = 3
	----------------
	dataBlock[0] = hd_info, ver = 0X1000100, datalen = 40, data below
	0000 - 31 2e 20 77 65 20 67 65-74 20 73 6f 6d 65 20 68   1. we get some h
	0010 - 61 72 64 77 61 72 65 20-69 6e 66 6f 20 66 72 6f   ardware info fro
	0020 - 6d 20 63 6c 69 65 6e 74-                          m client
	----------------
	dataBlock[1] = soft_info, ver = 0X1000100, datalen = 40, data below
	0000 - 32 2e 20 77 65 20 67 65-74 20 73 6f 6d 65 20 73   2. we get some s
	0010 - 6f 66 74 77 61 72 65 20-69 6e 66 6f 20 66 72 6f   oftware info fro
	0020 - 6d 20 63 6c 69 65 6e 74-                          m client
	----------------
	dataBlock[2] = stuff_info, ver = 0X1010001, datalen = 37, data below
	0000 - 32 2e 20 77 65 20 67 65-74 20 73 6f 6d 65 20 73   2. we get some s
	0010 - 74 75 66 66 20 69 6e 66-6f 20 66 72 6f 6d 20 63   tuff info from c
	0020 - 6c 69 65 6e 74                                    lient
	free map, g_mem_hook_map.size() = 0

测试工程实现

main.cpp

/*!
* \file main.cpp
*/

#include "my_openSSL_lib.h"
#include <openssl/crypto.h>
#include <openssl/bio.h>

#include <stdlib.h>
#include <stdio.h>
#include <assert.h>

#include "CMemHookRec.h"

#include "CMyDataContainerBase.h"

bool make_DataBuffer(uint8_t*& pBuf, int& lenBuf);
bool use_DataBuffer(uint8_t*& pBuf, int& lenBuf);

void my_openssl_app();

int main(int argc, char** argv)
{
	setvbuf(stdout, NULL, _IONBF, 0); // 清掉stdout缓存, 防止调用printf时阻塞
	mem_hook();

	my_openssl_app();

	mem_unhook();

	/*! run result
	header info :
	name = myapp_cfg
	buffer total len = 265
	buffer block cnt = 3
	----------------
	dataBlock[0] = hd_info, ver = 0X1000100, datalen = 40, data below
	0000 - 31 2e 20 77 65 20 67 65-74 20 73 6f 6d 65 20 68   1. we get some h
	0010 - 61 72 64 77 61 72 65 20-69 6e 66 6f 20 66 72 6f   ardware info fro
	0020 - 6d 20 63 6c 69 65 6e 74-                          m client
	----------------
	dataBlock[1] = soft_info, ver = 0X1000100, datalen = 40, data below
	0000 - 32 2e 20 77 65 20 67 65-74 20 73 6f 6d 65 20 73   2. we get some s
	0010 - 6f 66 74 77 61 72 65 20-69 6e 66 6f 20 66 72 6f   oftware info fro
	0020 - 6d 20 63 6c 69 65 6e 74-                          m client
	----------------
	dataBlock[2] = stuff_info, ver = 0X1010001, datalen = 37, data below
	0000 - 32 2e 20 77 65 20 67 65-74 20 73 6f 6d 65 20 73   2. we get some s
	0010 - 74 75 66 66 20 69 6e 66-6f 20 66 72 6f 6d 20 63   tuff info from c
	0020 - 6c 69 65 6e 74                                    lient
	free map, g_mem_hook_map.size() = 0
	*/

	return 0;
}

void my_openssl_app()
{
	uint8_t* pBuf = NULL;
	int lenBuf = 0;

	make_DataBuffer(pBuf, lenBuf);
	use_DataBuffer(pBuf, lenBuf);

	if (NULL != pBuf)
	{
		delete[] pBuf;
		pBuf = NULL;
	}
}

bool make_DataBuffer(uint8_t*& pBuf, int& lenBuf)
{
	CMyDataContainerBase* pDataContainer = NULL;
	bool b_rc = false;
	char szBuf[1024];

	do {
		pDataContainer = new CMyDataContainerBase();
		if (NULL == pDataContainer)
		{
			break;
		}

		// my app cfg 1.0.0.1
		pDataContainer->SetHeader("myapp_cfg", 0x01000001);

		// add data block - hdinfo 1.0.1.0
		strcpy(szBuf, "1. we get some hardware info from client");
		pDataContainer->addDataBuffer("hd_info", 0x01000100, (uint8_t*)szBuf, strlen(szBuf));

		// add data block - soft info 1.0.1.0
		strcpy(szBuf, "2. we get some software info from client");
		pDataContainer->addDataBuffer("soft_info", 0x01000100, (uint8_t*)szBuf, strlen(szBuf));

		// add data block - stuff info 1.1.0.1
		strcpy(szBuf, "2. we get some stuff info from client");
		pDataContainer->addDataBuffer("stuff_info", 0x01010001, (uint8_t*)szBuf, strlen(szBuf));

		if (!pDataContainer->GetTotalBuffer(pBuf, lenBuf))
		{
			assert(false);
			break;
		}

		b_rc = true;
	} while (false);

	if (NULL != pDataContainer)
	{
		delete pDataContainer;
		pDataContainer = NULL;
	}

	return b_rc;
}

bool use_DataBuffer(uint8_t*& pBuf, int& lenBuf)
{
	bool b_rc = false;
	CMyDataContainerBase* pDataContainer = NULL;
	TAG_DATA_CONTAINER_HEADER* pheader = NULL;
	TAG_DATA_BUFFER* pDataBuffer = NULL;
	int i = 0;

	do {
		pDataContainer = new CMyDataContainerBase();
		if (NULL == pDataContainer)
		{
			assert(false);
			break;
		}

		if (!pDataContainer->loadBuffer(pBuf, lenBuf))
		{
			assert(false);
			break;
		}

		if (!pDataContainer->getHeader(pheader))
		{
			assert(false);
			break;
		}

		printf("header info :\n");
		printf("name = %s\n", (char*)pheader->name_8d3);
		printf("buffer total len = %d\n", pheader->totoal_len);
		printf("buffer block cnt = %d\n", pheader->databuffer_cnt);
		
		for (i = 0; i < pheader->databuffer_cnt; i++)
		{
			printf("----------------\n");
			if (!pDataContainer->getDataBuffer(i, pDataBuffer))
			{
				assert(false);
				goto label_err;
			}

			printf("dataBlock[%d] = %s, ver = 0X%X, datalen = %d, data below\n", i, (char*)pDataBuffer->name_8d3, pDataBuffer->ver, pDataBuffer->len_data);
			BIO_dump_fp(stdout, pDataBuffer->pdata, pDataBuffer->len_data);
		}

		b_rc = true;
	} while (false);

label_err:
	return b_rc;
}


CMyDataContainerBase.h

//! \file CMyDataContainerBase.h
//! \note 将多个指针存到buffer中, 接收者将多个指针从数据块中提取出来用

#include <cstdint>
#include <list>
#ifndef __CMYDATACONTAINERBASE_H__
#define __CMYDATACONTAINERBASE_H__

// 数据容器形成buffer(文件)之后的格式
// TAG_DATA_CONTAINER_HEADER[1]
// TAG_DATA_BUFFER[n]
// data_block[n]

typedef struct _tag_data_container_header
{
	uint8_t name_8d3[13];
	int totoal_len; // 数据容器文件的大小, 从文件开头算起, 到文件结尾
	int databuffer_cnt;
	uint8_t hash[32];
}TAG_DATA_CONTAINER_HEADER;

typedef struct _tag_data_buffer
{
	uint8_t name_32[33];
	uint8_t* pdata;
	int posOnTotalMem; // 在数据文件中的位置, 从数据文件开头算起
	int len_data;

	_tag_data_buffer()
	{
		memset(name_32, 0, sizeof(name_32));
		pdata = NULL;
		posOnTotalMem = 0;
		len_data = 0;
	}
}TAG_DATA_BUFFER;

class CMyDataContainerBase
{
public:
	CMyDataContainerBase();
	virtual ~CMyDataContainerBase();

	void clear();

	// 组装者用的接口
	void SetHeader(const char* pszName8d3);
	void addDataBuffer(const char* pszName8d3, uint8_t* pdata, int len_data); // pdata内容会复制到类内部, 和外部指针无关

	// 如果要对数据做附加处理, 可以继承此类, 先调用父类接口实现, 再对数据做其他处理(e.g. encrypt/encode)

	// 只是更新了pBuf中的header中的hash值!!!
	bool update_hash(uint8_t*& pBuf, int& lenBuf); // 此时,应是数据都加完了,调用了GetTotalBuffer(), 然后送进update()来更新header中的hash

	virtual bool GetTotalBuffer(uint8_t*& pBuf, int& lenBuf); // 得到的pBuf需要调用者自己释放

	// 接受者用的接口
	// 如果要对数据做附加处理, 可以继承此类, 先对数据做其他处理(e.g. decrypt/decode), 再调用父类接口
	virtual bool loadBuffer(uint8_t* pBuf, int lenBuf);

	bool getHeader(TAG_DATA_CONTAINER_HEADER*& header);
	bool getDataBuffer(int index, TAG_DATA_BUFFER*& dataBuf);
	
private:
	TAG_DATA_CONTAINER_HEADER m_header;
	std::list<TAG_DATA_BUFFER*> m_list;
};

#endif // #ifndef __CMYDATACONTAINERBASE_H__



CMyDataContainerBase.cpp

//! \file CMyDataContainerBase.cpp

#include "pch.h"

#include "MemOpt/CMyDataContainerBase.h"
#include <cassert>
#include "openssl/evp.h"

#include "memOpt/my_debug_new_define.h"
#include <cipher/cipher_sha3_512.h>

CMyDataContainerBase::CMyDataContainerBase()
{
	clear();
}

CMyDataContainerBase::~CMyDataContainerBase()
{
	clear();
}

void CMyDataContainerBase::clear()
{
	std::list<TAG_DATA_BUFFER*>::iterator it;
	TAG_DATA_BUFFER* dataBuffer = NULL;

	memset(&m_header, 0, sizeof(m_header));

	for (it = m_list.begin(); it != m_list.end(); it++)
	{
		dataBuffer = *it;
		if (NULL != dataBuffer)
		{
			if (NULL != dataBuffer->pdata)
			{
				delete[] dataBuffer->pdata;
				dataBuffer->pdata = NULL;
			}

			// 这是我今天上午修正的内存泄漏
			delete dataBuffer;
			dataBuffer = NULL;
		}
	}

	m_list.clear();
}

void  CMyDataContainerBase::SetHeader(const char* pszName8d3)
{
	do {
		if ((NULL == pszName8d3) || (strlen(pszName8d3) > sizeof(m_header.name_8d3)))
		{
			assert(false);
			break;
		}

		strcpy((char*)m_header.name_8d3, pszName8d3);
	} while (false);
}

void CMyDataContainerBase::addDataBuffer(const char* pszName8d3, uint8_t* pdata, int len_data)
{
	TAG_DATA_BUFFER* pDataBuffer = NULL;
	int len = 0;
	do {
		if (NULL != pszName8d3)
		{
			len = (int)strlen(pszName8d3);
		}

		if ((NULL == pszName8d3) || (strlen(pszName8d3) >= sizeof(TAG_DATA_BUFFER::name_32)))
		{
			assert(false);
			break;
		}

		if ((NULL == pdata) || (len_data <= 0))
		{
			assert(false);
			break;
		}

		pDataBuffer = new TAG_DATA_BUFFER;
		if (NULL == pDataBuffer)
		{
			assert(false);
			break;
		}

		memset(pDataBuffer, 0, sizeof(TAG_DATA_BUFFER));
		strcpy((char*)pDataBuffer->name_32, pszName8d3);
		pDataBuffer->posOnTotalMem = 0;
		pDataBuffer->len_data = len_data;
		pDataBuffer->pdata = new uint8_t[pDataBuffer->len_data];
		if (NULL == pDataBuffer->pdata)
		{
			assert(false);
			break;
		}

		memcpy(pDataBuffer->pdata, pdata, pDataBuffer->len_data);

		m_list.push_back(pDataBuffer);
	} while (false);
}

bool CMyDataContainerBase::update_hash(uint8_t*& pBuf, int& lenBuf)
{
	bool b_rc = false;
	bool b = false;
	TAG_DATA_CONTAINER_HEADER* pHeader = NULL;
	CCipherSha3_256 hash;

	do {
		if ((NULL == pBuf) || (lenBuf <= 0))
		{
			break;
		}

		pHeader = (TAG_DATA_CONTAINER_HEADER*)(pBuf + 0);
		memset(pHeader->hash, 0, sizeof(pHeader->hash));

		b = hash.begin();
		assert(true == b);

		hash.update(pBuf, lenBuf);
		assert(true == b);

		hash.end();
		assert(true == b);

		assert(hash.get_md_len() == sizeof(pHeader->hash));
		memcpy(pHeader->hash, hash.get_md(), hash.get_md_len());

		b_rc = true;
	} while (false);

	return b_rc;
}

bool CMyDataContainerBase::GetTotalBuffer(uint8_t*& pBuf, int& lenBuf)
{
	bool b_rc = false;
	pBuf = NULL;
	lenBuf = 0;

	int szList = 0;
	std::list<TAG_DATA_BUFFER*>::iterator it;
	TAG_DATA_CONTAINER_HEADER* pHeader = NULL;
	TAG_DATA_BUFFER* pDataBuffer = NULL;
	TAG_DATA_BUFFER* pDataBufferMem = NULL;
	uint8_t* pDataBufferMemData = NULL; // pBuf用的
	int i = 0;
	int lenDataTotalNow = 0;

	do {
		// 数据容器形成buffer(文件)之后的格式
		// TAG_DATA_CONTAINER_HEADER[1]
		// TAG_DATA_BUFFER[n]
		// data_block[n]
		
		szList = (int)m_list.size();
		lenBuf = sizeof(TAG_DATA_CONTAINER_HEADER) + szList * sizeof(TAG_DATA_BUFFER);

		lenDataTotalNow = 0;
		for (i = 0, it = m_list.begin(); it != m_list.end(); it++, i++)
		{
			pDataBuffer = *it;
			if (NULL == pDataBuffer)
			{
				assert(false);
				goto label_err;
			}

			lenBuf += pDataBuffer->len_data;

			pDataBuffer->posOnTotalMem = (int)(sizeof(TAG_DATA_CONTAINER_HEADER) + szList * sizeof(TAG_DATA_BUFFER) + lenDataTotalNow);
			lenDataTotalNow += pDataBuffer->len_data;
		}

		pBuf = (uint8_t*)OPENSSL_malloc(lenBuf);
		if (NULL == pBuf)
		{
			assert(false);
			break;
		}

		memset(pBuf, 0, lenBuf);

		// 填充header;
		m_header.databuffer_cnt = szList;
		m_header.totoal_len = lenBuf;
		memset(m_header.hash, 0, sizeof(m_header.hash));

		// copy header
		pHeader = (TAG_DATA_CONTAINER_HEADER*)(pBuf + 0);
		memcpy(pHeader, &m_header, sizeof(m_header));

		// 依次填充DataBuffer
		for (i= 0, it = m_list.begin(); it != m_list.end(); it++, i++)
		{
			pDataBuffer = *it;

			pDataBufferMem = (TAG_DATA_BUFFER*)(pBuf + sizeof(TAG_DATA_CONTAINER_HEADER) + i * sizeof(TAG_DATA_BUFFER));
			memcpy(pDataBufferMem, pDataBuffer, sizeof(TAG_DATA_BUFFER));
			pDataBufferMem->pdata = NULL; // 放入buffer之后,pdata就没用了,而且会影响算hash.

			pDataBufferMemData = (pBuf + pDataBuffer->posOnTotalMem);
			memcpy(pDataBufferMemData, pDataBuffer->pdata, pDataBuffer->len_data);
		}

		b_rc = true;
	} while (false);

label_err:

	return b_rc;
}

bool CMyDataContainerBase::loadBuffer(uint8_t* pBuf, int lenBuf)
{
	bool b_rc = false;
	TAG_DATA_CONTAINER_HEADER* pHeader = NULL;
	TAG_DATA_BUFFER* pDataBuf = NULL;
	int iTotalLenNow = 0;
	int i = 0;

	do {
		if ((NULL == pBuf) || (lenBuf <= 0))
		{
			break;
		}

		clear();

		// 数据容器形成buffer(文件)之后的格式
		// TAG_DATA_CONTAINER_HEADER[1]
		// TAG_DATA_BUFFER[n]
		// data_block[n]

		iTotalLenNow += sizeof(TAG_DATA_CONTAINER_HEADER);
		if (iTotalLenNow > lenBuf)
		{
			break;
		}

		pHeader = (TAG_DATA_CONTAINER_HEADER*)pBuf;
		iTotalLenNow += (pHeader->databuffer_cnt * sizeof(TAG_DATA_BUFFER));
		if (iTotalLenNow > lenBuf)
		{
			break;
		}

		for (i = 0; i < pHeader->databuffer_cnt; i++)
		{
			pDataBuf = (TAG_DATA_BUFFER*)(pBuf + sizeof(TAG_DATA_CONTAINER_HEADER) + sizeof(TAG_DATA_BUFFER));
			if ((pDataBuf->posOnTotalMem + pDataBuf->len_data) > lenBuf)
			{
				goto label_err;
			}
		}

		// 到此, 数据格式基本正确
		// 将数据载入 m_header, m_list
		memcpy(&m_header, (pBuf + 0), sizeof(TAG_DATA_CONTAINER_HEADER));
		for (i = 0; i < pHeader->databuffer_cnt; i++)
		{
			pDataBuf = new TAG_DATA_BUFFER;
			if (NULL == pDataBuf)
			{
				assert(false);
				goto label_err;
			}

			memcpy(pDataBuf, (pBuf + sizeof(TAG_DATA_CONTAINER_HEADER) + i * sizeof(TAG_DATA_BUFFER)), sizeof(TAG_DATA_BUFFER));
			pDataBuf->pdata = new uint8_t[pDataBuf->len_data];
			if (NULL == pDataBuf->pdata)
			{
				assert(false);
				goto label_err;
			}

			memcpy(pDataBuf->pdata, pBuf + pDataBuf->posOnTotalMem, pDataBuf->len_data);
			m_list.push_back(pDataBuf);
		}

		b_rc = true;
	} while (false);

label_err:
	return b_rc;
}

bool CMyDataContainerBase::getHeader(TAG_DATA_CONTAINER_HEADER*& header)
{
	header = &m_header;
	return true;
}

bool CMyDataContainerBase::getDataBuffer(int index, TAG_DATA_BUFFER*& dataBuf)
{
	bool b_rc = false;
	std::list<TAG_DATA_BUFFER*>::iterator it;
	int i = 0;
	TAG_DATA_BUFFER* pDataBuffer = NULL;

	do {
		if (index >= this->m_header.databuffer_cnt)
		{
			break;
		}

		for (i = 0, it = m_list.begin(); it != m_list.end(); it++, i++)
		{
			if (i != index)
			{
				continue;
			}

			pDataBuffer = *it;
			if (NULL == pDataBuffer)
			{
				assert(false);
				goto label_err;
			}

			dataBuf = pDataBuffer;
			b_rc = true;
			break;
		}
	} while (false);
	
label_err:
	return b_rc;
}


备注

如果不想用户直接能分析提交的内容(因为buffer的内容有可能包含ascii字符, 人眼可以分辨), 现在能想到的方法有2种:

  • 在执行GetTotalBuffer()后, 得到总的buffer, 对buffer做编解码/加解密处理
  • 直接从CMyDataContainerBase继承一个子类, 重载GetTatalBuffer()/loadBuffer(), 对提交/载入的数据在子类中直接处理.

END

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值