c++ 實現高效緩存(鏈式buffer)

如果我們從網絡端接收的數據是不定長度的,不能提前分配好網絡緩存大小,則可以選擇使用鏈式緩存的實現方式。鏈式緩存主要是分配固定大小的緩存鏈保存數據,一個管理器去管理這些緩存鏈。

鏈式緩存示例:

//一種鏈式緩衝
//ringbuffer是固定長度,不能夠擴展,鏈式buffer可以任意擴充
/**
 * buffer
 *     *first--chain buffer [1024]
 *             |--chain buffer
 *             |--chain buffer
 *     *datap--|--chain buffer
 *     *last---chain buffer
 * */

#include <cstdio>
#include <iostream>
#include <cstring>


using namespace std;

struct chain_buffer_mgr
{
	struct chain_buffer* first;
	struct chain_buffer* last;
	struct chain_buffer* last_datap; // 指向最後保存數據的緩存鏈
	size_t total_len;                // 所有鏈緩存保存的總共數據
};

struct chain_buffer
{
	int read_pos;
	int write_pos;
	struct chain_buffer* next;
	size_t buffer_len;
	char* buffer;
};

#define BUFFER_CHAIN_SIZE sizeof(struct chain_buffer)
#define BUFFER_CHAIN_EXTRA (t, c)(t *)((struct chain_buffer *)(c) + 1) //指向chain buffer 緩存區

class ChainBuffer
{
public:
	ChainBuffer() {}
	~ChainBuffer(){}
	void Clear()
	{
		struct chain_buffer* first = m_oBufferMgr.first;
		while (first != nullptr)
		{
			delete[] first->buffer;
			struct chain_buffer* next = first->next;
			delete first;
			first = next;
		}
		m_oBufferMgr.first = nullptr;
		m_oBufferMgr.last_datap = nullptr;
		m_oBufferMgr.last = nullptr;
	}
	void Init(int bufsize)
	{
		m_nBufSize = bufsize;
		chain_buffer* chain = new chain_buffer;
		chain->buffer = new char[m_nBufSize + 1];
		chain->buffer[m_nBufSize] = '\0';
		chain->next = nullptr;
		chain->read_pos = chain->write_pos = 0;
		chain->buffer_len = m_nBufSize;
		m_oBufferMgr.first = m_oBufferMgr.last = chain;
		m_oBufferMgr.last_datap = nullptr;
		m_oBufferMgr.total_len = 0;
	}

	void Init(int chains, int bufsize)
	{
		m_nBufSize = bufsize;
		m_oBufferMgr.first = nullptr;
		m_oBufferMgr.last = nullptr;
		m_oBufferMgr.total_len = 0;
		m_oBufferMgr.last_datap = nullptr;
		for (int i = 0; i < chains; ++i)
		{
			chain_buffer* chain = new chain_buffer;
			chain->buffer = new char[m_nBufSize + 1];
			chain->buffer[m_nBufSize] = '\0';
			chain->next = nullptr;
			chain->read_pos = chain->write_pos = 0;
			chain->buffer_len = m_nBufSize;
			if (m_oBufferMgr.first == nullptr)
			{
				m_oBufferMgr.first = chain;
				m_oBufferMgr.last = chain;
			}
			else
			{
				m_oBufferMgr.last->next = chain;
				m_oBufferMgr.last = chain;
			}
		}
	}

	void Write(const char* buf, int size)
	{
		m_oBufferMgr.total_len += size;
		chain_buffer* chain = nullptr;
		if (m_oBufferMgr.last_datap == nullptr) // init
		{
			chain = m_oBufferMgr.first;
		}
		else
		{
			chain = m_oBufferMgr.last_datap;
		}
		int write_len = 0;
		int can_write_len = 0;
		while (chain && size > 0)
		{
			if (chain->write_pos > 0 && size >= (m_nBufSize - chain->write_pos))
			{
				can_write_len = m_nBufSize - chain->write_pos;
			}
			if (chain->write_pos == 0 && size >= m_nBufSize)
			{
				can_write_len = m_nBufSize;
			}
			else
			{
				can_write_len = size;
			}
			memcpy(chain->buffer + chain->write_pos, buf + write_len, can_write_len);
			size -= can_write_len;
			chain->write_pos += can_write_len;
			write_len += can_write_len;
			m_oBufferMgr.last_datap = chain;
			if (chain->next == nullptr)
			{
				chain_buffer* chain_next = new chain_buffer;
				chain_next->buffer = new char[m_nBufSize + 1];
				chain_next->buffer[m_nBufSize] = '\0';
				chain_next->next = nullptr;
				chain_next->write_pos = chain->read_pos = 0;
				chain_next->buffer_len = m_nBufSize;
				m_oBufferMgr.last = chain_next;
				chain->next = chain_next;
				chain = chain_next;
			}
			else
			{
				chain = chain->next;
			}
			
		}
	}
	void Read(char* buf, int size)
	{
		chain_buffer* chain = m_oBufferMgr.first;
		int read_len = 0;
		int can_read_len = 0;
		while (chain && size > 0)
		{
			can_read_len = chain->write_pos - chain->read_pos;
			if (can_read_len >= size)
			{
				can_read_len = size;
			}
			memcpy(buf + read_len, chain->buffer + chain->read_pos, can_read_len);
			m_oBufferMgr.total_len -= can_read_len;
			read_len += can_read_len;
			size -= can_read_len;
			chain->read_pos += can_read_len;
			if (chain->read_pos == chain->buffer_len)
			{
				chain->read_pos = 0;
				chain->write_pos = 0;
				chain_buffer* chain_tmp = chain;
				chain = chain->next;
				m_oBufferMgr.first = chain;
				m_oBufferMgr.last->next = chain_tmp;
				m_oBufferMgr.last = chain_tmp;
				chain_tmp->next = nullptr;
			}
		}
	}

	int TotalDataSize()
	{
		return m_oBufferMgr.total_len;
	}

	chain_buffer_mgr& GetBufferMgr()
	{
		return m_oBufferMgr;
	}

private:
	size_t m_nBufSize;
	chain_buffer_mgr m_oBufferMgr;
};

int main()
{
	ChainBuffer chainBuffer;
	chainBuffer.Init(2,10);
	const char* w1 = "abcdefghljklmnopqrstuvwxyz1234567890";
	cout << w1 << endl;
	chainBuffer.Write(w1, strlen(w1));
	cout << chainBuffer.TotalDataSize() << endl;
	chain_buffer* chain = chainBuffer.GetBufferMgr().first;
	while (chain)
	{
		cout << chain->buffer << endl;
		chain = chain->next;
	}
	cout << endl;
	char buf[22];
	memset(buf, 0, sizeof(buf));
	chainBuffer.Read(buf, 21);
	cout << buf << endl;
	cout << endl;
	chain = chainBuffer.GetBufferMgr().first;
	while (chain)
	{
		cout << chain->buffer << endl;
		chain = chain->next;
	}
	chainBuffer.Clear();
}

 

上面是固定長度的鏈式緩存,不能很好的應用與socket 接收,如果直接使用read、write 讀寫緩存,可以參考下面提供的實現

https://github.com/Addision/EventServer/blob/master/SeEvent/SocketBuffer.h

使用方式:

https://github.com/Addision/EventServer/blob/master/SeNet/Session.h

https://github.com/Addision/EventServer/blob/master/SeNet/SeNet.cpp   (EventRead、EventWrite 兩個函數)

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章