如果我們從網絡端接收的數據是不定長度的,不能提前分配好網絡緩存大小,則可以選擇使用鏈式緩存的實現方式。鏈式緩存主要是分配固定大小的緩存鏈保存數據,一個管理器去管理這些緩存鏈。
鏈式緩存示例:
//一種鏈式緩衝
//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 兩個函數)