// 由于TCP是不分界限的字节流数据,一般在从socket 内核缓冲区读数据时根本不知道缓冲区里有多少数据。
// 可以通过recv 的MSG_PEEK 标致位窥看数据的长度, 再动态分配存储的缓冲区,但每次读取系统调用窥看和分配,
// 会影响程序的的性能.或者是在读和处理的速度不一致时,又不想多次拷贝,一次性没处理完的数据还继续保存在缓冲区里。
// 我们需要有一个自动扩展分配的缓冲来存储。#define ALLOC_LEN (10 * 1024) //首次申请缓存大小, 默认为10K
#define MAX_ALLOC_LEN ((1024 * ALLOC_LEN)) //最大可申请的接收缓存(10 M)
#define REALLOC_BORDER_LEN ((10 * 1024) / 80) //重新申请的边界大小(首次分配的八十分之一), 注:边界大小可以自己定义
//数据信息缓冲
class CDataBuf
{
public:
//构造函数
CDataBuf()
{
buf = (char*)malloc(ALLOC_LEN + 1);
if(buf == NULL)
{
buf_len = 0;
//LOG("Call realloc() error");
}
else
{
buf_len = ALLOC_LEN;
}
Clear();
}
//析构函数
~CDataBuf()
{
if(NULL != buf)
{
free(buf);
buf = NULL;
}
buf_len = 0;
Clear();
}
//清空
void Clear()
{
data_size = 0;
offset = 0;
}
//重置,复位到原来的大小
void Reset()
{
if(buf_len != ALLOC_LEN)
{
buf = (char*)realloc(buf, ALLOC_LEN);
if(buf == NULL)
{
buf_len = 0;
//LOG("Call realloc() error");
}
else
{
buf_len = ALLOC_LEN;
}
}
Clear();
}
//功能: 1.检查缓冲区的数据是否达到再分配的边界值, 如果达到分配的边界值则以指数级再分配,并把原数据拷贝到新缓冲区中.
// 2.检查缓冲区已分配的空间是否达到最大分配值,如果达到则返回false.
//输入: 无
//输出: 成功 true; 失败 false;
bool CheckBuf()
{
if((buf_len - data_size) > REALLOC_BORDER_LEN)
{
//缓冲区的空闲长度还未达到再分配的边界
return true;
}
//缓冲区的空闲长度已达到再分配的边界
unsigned int realloc_len = buf_len << 1;
do
{
if(realloc_len > MAX_ALLOC_LEN)
{
//增长后再分配的长度超过分配的最大值
if(MAX_ALLOC_LEN > buf_len)
{
//目前的长度还未达到最大长度,以最大长度分配
realloc_len = MAX_ALLOC_LEN;
break;
}
if(data_size >= buf_len)
{
//缓冲区的数据长度已经达到缓冲区的最大长度, 返回失败
//LOG("data_size:%u, buf_len:%u\n", data_size, buf_len);
return false;
}
//缓冲区还有空间
return true;
}
}while(0);
buf = (char*)realloc(buf, realloc_len + 1);
if(buf == NULL)
{
//分配失败
buf_len = 0;
Clear();
//LOG("Call realloc() error");
return false;
}
else
{
//重新分配成功
buf_len = realloc_len;
}
return true;
}
public:
//缓冲区指针
char* buf;
//缓冲区长度
unsigned int buf_len;
//缓冲区里数据的长度
unsigned int data_size;
//已处理的数据偏移长度
unsigned int offset;
};
//------------------ 举例缓冲区的处理 ------------------------
int readData(char* buf, const int read_len)
{
int len = sprintf(buf, "%s", "abccccccccccccccc");
return len;
}
int processData(const char* buf, const int data_len)
{
printf(buf);
return 0;
}
int main(int argc, char ** argv)
{
CDataBuf read_buf;
int read_bytes = 0;
int proc_bytes = 0;
do
{
if(!read_buf.CheckBuf())
{
//LOG("ERROR:Data buf not space.")
//这里有可能是处理太慢,导致缓冲区满, 可以在这加个while processData(), 把数据处理完成再读
break;
}
//读数据到缓冲区
read_bytes = readData(read_buf.buf + read_buf.data_size, read_buf.buf_len - read_buf.data_size);
if(read_bytes <= 0 )
{
//错误,或结束
break;
}
//读到的数据累加到缓冲区已有的数据长度里
read_buf.data_size += read_bytes;
//处理缓冲区的数据
proc_bytes = processData(read_buf.buf + read_buf.offset, read_buf.data_size - read_buf.offset);
if(proc_bytes <= 0 )
{
//错误,或结束
break;
}
if(proc_bytes < (read_buf.data_size - read_buf.offset))
{
//如果缓冲区的数据没有处理完
read_buf.offset += proc_bytes;
}
else
{
//如果处理了缓冲区的所有数据,则清空重头开始存放
read_buf.data_size = 0;
read_buf.data_size = 0;
}
}while(true);
//最后退出需要再次校验缓冲区里是否还有数据
while((read_buf.data_size - read_buf.offset) > 0)
{
proc_bytes = processData(read_buf.buf + read_buf.data_size, read_buf.data_size - read_buf.offset);
if(proc_bytes <= 0 )
{
//错误,或结束
break;
}
read_buf.offset += proc_bytes;
};
}