1:背景介绍:

在日常业务开发中,使用缓冲区进行临时存储的业务场景也比较多,如tcp每个连接底层都维持一个发送缓冲区和接收缓冲区。

实现一个ringbuffer,做代码备用。(可以考虑如何对ringbuffer进行扩大?)

//实现ringbuffer,其实就是申请一块内存,对塞入数据和取出数据位置分别进行管理
typedef struct RINGBUFF_T{void * data;unsigned int size;unsigned int read_pos;   //数据起始位置unsigned int write_pos;  //数据终止位置
}ringbuffer_t;

2:测试代码:

这里的代码是我为了测试,实现一个ringbuffer进行管理。

这里只考虑了单线程的逻辑实现,多线程需要适配一下。。。

这里在取数据时,有一定的设计,考虑取一个包的数据(可以自己适配调整)。

2.1:my_ringbuffer.h

#ifndef __RINGBUFFER_H_
#define __RINGBUFFER_H_typedef struct RINGBUFF_T{void * data;unsigned int size;unsigned int read_pos;   //数据起始位置unsigned int write_pos;  //数据终止位置
}ringbuffer_t;//创建ringbuffer
ringbuffer_t * ringbuffer_create(unsigned int size);
//销毁ringbuffer
void ringbuffer_destroy(ringbuffer_t * ring_buffer);//往ringbuffer中存数据 写入
int ringbuffer_put(ringbuffer_t * ring_buffer, const char* buffer, unsigned int len);
//判断是否是完整的数据  然后进行处理
int ringbuffer_get_len(ringbuffer_t *ring_buffer);
//依赖ringbuffer_get_len 返回值申请内存,取出ring_buffer中的数据
int ringbuffer_get(ringbuffer_t * ring_buffer, char * buffer, unsigned int len);//基本接口 外部基本不用,但是函数内部有使用
//重置缓冲区
void ringbuffer_reset(ringbuffer_t * ring_buffer);
//ringbuffer已经使用的内存空间的大小
int ringbuffer_use_len(ringbuffer_t * ring_buffer);
//ringbuffer没有使用的内存的大小
int ringbuffer_space_len(ringbuffer_t * ring_buffer);//基本的判空和判满接口
int ringbuffer_isempty(ringbuffer_t * ring_buffer);
int ringbuffer_isfull(ringbuffer_t * ring_buffer);// int get_ringbuffer_size(ringbuffer_t * ring_buffer);
#endif //__RINGBUFFER_H_

2.2:my_ringbuffer.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>#include "my_ringbuffer.h"static inline __attribute__((const))
int is_power_of_2(unsigned long n)
{return (n != 0 && ((n & (n - 1)) == 0));
}static unsigned long roundup_power_of_two(unsigned long n)
{if((n & (n-1)) == 0)return n;unsigned long maxulong = (unsigned long)((unsigned long)~0);unsigned long andv = ~(maxulong&(maxulong>>1));while((andv & n) == 0)andv = andv>>1;return andv<<1;
}//创建ringbuffer
ringbuffer_t * ringbuffer_create(unsigned int size)
{//对入参进行校验 并且是2的次方if (!is_power_of_2(size)) {size = roundup_power_of_two(size);}ringbuffer_t * ring_buffer;ring_buffer = (ringbuffer_t*)malloc(sizeof(*ring_buffer));if(ring_buffer == NULL){printf("create ringbuffer error \n");return NULL;}ring_buffer->data = (void*)malloc(size);if(ring_buffer->data == NULL){printf("create ringbuffer data error \n");free(ring_buffer);return NULL;}ring_buffer->size = size;ring_buffer->read_pos = 0;ring_buffer->write_pos = 0;return ring_buffer;
}//销毁ringbuffer
void ringbuffer_destroy(ringbuffer_t * ring_buffer)
{if(ring_buffer){if(ring_buffer->data){free(ring_buffer->data);ring_buffer->data = NULL;}free(ring_buffer);ring_buffer = NULL;}
}//往ringbuffer中存数据 写入
int ringbuffer_put(ringbuffer_t * ring_buffer, const char* buffer, unsigned int len)
{if(ring_buffer->write_pos >=ring_buffer->read_pos &&(len <(ring_buffer->size - ring_buffer->write_pos +ring_buffer->read_pos))){//进行拷贝if(ring_buffer->size - ring_buffer->write_pos >len){memcpy(ring_buffer->data + ring_buffer->write_pos, buffer, len);ring_buffer->write_pos += len;}else{unsigned int right_space_len = ring_buffer->size - ring_buffer->write_pos;memcpy(ring_buffer->data + ring_buffer->write_pos, buffer, right_space_len);memcpy(ring_buffer->data, buffer+right_space_len, len - right_space_len);ring_buffer->write_pos = len - right_space_len;}return 0;}if(ring_buffer->write_pos <ring_buffer->read_pos && (ring_buffer->read_pos - ring_buffer->write_pos) >len){memcpy(ring_buffer->data + ring_buffer->write_pos, buffer, len);ring_buffer->write_pos += len;return 0;}return -1;
}//判断是否是完整的数据  然后进行处理
int ringbuffer_get_len(ringbuffer_t *ring_buffer)
{//对ringbuffer中的数据做判断解析  如果是完整的数据  则提取出去if(ringbuffer_use_len(ring_buffer) < strlen("FFFF0D0A<header><tail>0D0AFEFE")){printf("ringbuffer data is error [%d], [%ld]\n", ringbuffer_use_len(ring_buffer),  strlen("FFFF0D0A<header><tail>0D0AFEFE"));return -1;}//判断是否是终结的字段const char* end_str = "<tail>0D0AFEFE";char check_end_str[20] = {0};if(ring_buffer->write_pos >strlen(end_str)){memcpy(check_end_str, ring_buffer->data+ring_buffer->write_pos - (strlen(end_str)),  strlen(end_str));}else{unsigned int left_len = ring_buffer->write_pos;memcpy(check_end_str, ring_buffer->data +ring_buffer->size - (strlen(end_str) - left_len), ring_buffer->size - (strlen(end_str) - left_len));memcpy(check_end_str + (strlen(end_str) - left_len), ring_buffer->data, left_len);}printf("get check_end_str is %s \n", check_end_str);char * ret_addr = strstr(check_end_str, end_str);if(ret_addr == NULL){return -1;}if(check_end_str - ret_addr != 0){printf("DDDDD :why end string is error");return -1;}return ringbuffer_use_len(ring_buffer);
}//从ringbuffer中取数据做处理, 判断接收到的字符是否是终结符号,就可以去做处理
//取完数据后重置ringbuffer的位置  读取
int ringbuffer_get(ringbuffer_t * ring_buffer, char * buffer, unsigned int len)
{//这里建立在ringbuffer_get_len 的基础上,传入入参,取出数据int data_len = ringbuffer_use_len(ring_buffer);if(data_len >= len){printf("para buffer is not enough space \n");return -1;}if(ring_buffer->write_pos >ring_buffer->read_pos ){printf("get data from ringbuffer len: [%d] \n", ring_buffer->write_pos - ring_buffer->read_pos);memcpy(buffer, ring_buffer->data + ring_buffer->read_pos, data_len);}else{memcpy(buffer, ring_buffer->data+ring_buffer->read_pos, ring_buffer->size - ring_buffer->read_pos);memcpy(buffer+ring_buffer->size - ring_buffer->read_pos, ring_buffer->data, data_len - (ring_buffer->size - ring_buffer->read_pos));}ring_buffer->write_pos = 0;ring_buffer->read_pos = 0;return 0;
}//直接从socket中读数据放入ringbuffer中也可以
int ringbuffer_get_from_dev()
{return 0;
}
//直接从ringbuffer中取数据用socket进行发送
int ringbuffer_put_to_dev()
{return 0;
}void ringbuffer_reset(ringbuffer_t * ring_buffer)
{ring_buffer->read_pos = ring_buffer->write_pos = 0;
}int ringbuffer_use_len(ringbuffer_t * ring_buffer)
{if(ring_buffer->write_pos >= ring_buffer->read_pos){return ring_buffer->write_pos-ring_buffer->read_pos;}return ring_buffer->write_pos + ring_buffer->size - ring_buffer->read_pos;
}int ringbuffer_space_len(ringbuffer_t * ring_buffer)
{if(ring_buffer->write_pos >= ring_buffer->read_pos){return ring_buffer->read_pos +(ring_buffer->size - ring_buffer->write_pos);}return ring_buffer->read_pos - ring_buffer->write_pos;
}int ringbuffer_isempty(ringbuffer_t * ring_buffer)
{return ringbuffer_use_len(ring_buffer) == 0? 0 :-1;
}int ringbuffer_isfull(ringbuffer_t * ring_buffer)
{return ringbuffer_space_len(ring_buffer) == 0? 0 :-1;
}// int get_ringbuffer_size(ringbuffer_t * ring_buffer)
// {//  return ring_buffer->size;
// }

2.3:my_ringbuffer_test.c

/************************************************
info: 对ringbuffer的封装做简单的测试
data: 2022/02/10
author: hlp
************************************************/#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "tcp_ringbuffer.h"int main()
{//申请一个ringbuffer ringbuffer_t * ringbuff = ringbuffer_create(128);printf("ringbuffer_create size is : %d \n", ringbuff->size);printf("ringbuffer isempty [%d] \n", ringbuffer_isempty(ringbuff));printf("ringbuffer isfull [%d] \n", ringbuffer_isfull(ringbuff));printf("ringbuffer used len is [%d] \n",ringbuffer_use_len(ringbuff));printf("ringbuffer space len is [%d] \n", ringbuffer_space_len(ringbuff));ringbuffer_destroy(ringbuff);//判断基本的条件ringbuff = ringbuffer_create(129);printf("ringbuffer_create size is : %d \n", ringbuff->size);printf("ringbuffer isempty [%d] \n", ringbuffer_isempty(ringbuff));printf("ringbuffer isfull [%d] \n", ringbuffer_isfull(ringbuff));printf("ringbuffer used len is [%d] \n",ringbuffer_use_len(ringbuff));printf("ringbuffer space len is [%d] \n", ringbuffer_space_len(ringbuff));ringbuffer_destroy(ringbuff);//给ringbuff中塞入一定的数据查看相关的基本信息ringbuff = ringbuffer_create(129);const char* str_data = "FFFF0D0A<header><tail>0D0AFEFE";//给ringbuffer中塞入一定的数据,进行获取查看ringbuffer_put(ringbuff, str_data, strlen(str_data));printf("set data size is : %lu, ringbuff size is %d \n", strlen(str_data), ringbuff->size);printf("ringbuffer isempty [%d] \n", ringbuffer_isempty(ringbuff));printf("ringbuffer isfull [%d] \n", ringbuffer_isfull(ringbuff));printf("ringbuffer used len is [%d] \n",ringbuffer_use_len(ringbuff));printf("ringbuffer space len is [%d] \n", ringbuffer_space_len(ringbuff));int data_len = ringbuffer_get_len(ringbuff);if(data_len == -1){printf("error of ringbuff data \n");}else{printf("ringbuff data len is %d \n", data_len);}char * data_exec;data_exec = (char*)malloc(data_len +1);memset(data_exec, 0, data_len +1);printf("sizeof data_exec is %lu \n", sizeof(data_exec));ringbuffer_get(ringbuff, data_exec, data_len +1);printf("ringbuff get data is :%s \n",data_exec);printf("ringbuffer isempty [%d] \n", ringbuffer_isempty(ringbuff));printf("ringbuffer isfull [%d] \n", ringbuffer_isfull(ringbuff));printf("ringbuffer used len is [%d] \n",ringbuffer_use_len(ringbuff));printf("ringbuffer space len is [%d] \n", ringbuffer_space_len(ringbuff));ringbuffer_destroy(ringbuff);if(data_exec !=NULL){free(data_exec);data_exec = NULL;}printf("******************test of more package check***********************\n");const char* data_str_test = "FFFF0D0A<header><tail>0D0AFEFE";const char* data_str_test1 = "FFFF0D0A<header>111<tail>0D0AFEFE";const char* data_str_test2 = "FFFF0D0A<header>222<tail>0D0AFEFE";const char* data_str_test3 = "FFFF0D0A<header><tail>0D0AFEFE";const char* data_str_test4 = "FFFF0D0A<header><tail>0D0AFEFE";const char* data_str_error = "FFFF0D0A<header>test error";//试着塞多个数据 能取出来吗?ringbuff = ringbuffer_create(129);ringbuffer_put(ringbuff, data_str_test, strlen(data_str_test));printf("put one data. ringbuffer used len is [%d] \n",ringbuffer_use_len(ringbuff));printf("put one data.  ringbuffer space len is [%d] \n", ringbuffer_space_len(ringbuff));ringbuffer_put(ringbuff, data_str_test1, strlen(data_str_test1));printf("put two data. ringbuffer used len is [%d] \n",ringbuffer_use_len(ringbuff));printf("put two data.  ringbuffer space len is [%d] \n", ringbuffer_space_len(ringbuff));ringbuffer_put(ringbuff, data_str_test2, strlen(data_str_test2));printf("put three data. ringbuffer used len is [%d] \n",ringbuffer_use_len(ringbuff));printf("put three data.  ringbuffer space len is [%d] \n", ringbuffer_space_len(ringbuff));printf("ringbuffer is not empty [%d] \n", ringbuffer_isempty(ringbuff));printf("ringbuffer is not full [%d] \n", ringbuffer_isfull(ringbuff));int test_get_len = ringbuffer_get_len(ringbuff);if(test_get_len == -1){printf("error of ringbuff data \n");}else{printf("get ringbuff has data len is %d \n", test_get_len);}data_exec = (char*)malloc(test_get_len +1);memset(data_exec, 0, test_get_len +1);ringbuffer_get(ringbuff, data_exec, test_get_len +1);printf("ringbuff get data is :%s \n",data_exec);printf("get all data used len is [%d] \n",ringbuffer_use_len(ringbuff));printf("get all data space len is [%d] \n", ringbuffer_space_len(ringbuff));printf("ringbuffer isempty [%d] \n", ringbuffer_isempty(ringbuff));printf("ringbuffer is not full [%d] \n", ringbuffer_isfull(ringbuff));ringbuffer_destroy(ringbuff);if(data_exec !=NULL){free(data_exec);data_exec = NULL;}ringbuff = ringbuffer_create(129);ringbuffer_put(ringbuff, data_str_test, strlen(data_str_test));ringbuffer_put(ringbuff, data_str_error, strlen(data_str_error));test_get_len = ringbuffer_get_len(ringbuff);if(test_get_len == -1){printf("error of ringbuff data \n");}else{printf("get ringbuff has data len is %d \n", test_get_len);}ringbuffer_put(ringbuff, data_str_test, strlen(data_str_test));test_get_len = ringbuffer_get_len(ringbuff);if(test_get_len == -1){printf("error of ringbuff data \n");}else{printf("get ringbuff has data len is %d \n", test_get_len);}data_exec = (char*)malloc(test_get_len +1);memset(data_exec, 0, test_get_len +1);ringbuffer_get(ringbuff, data_exec, test_get_len +1);printf("ringbuff get data is :%s \n",data_exec);printf("get all data used len is [%d] \n",ringbuffer_use_len(ringbuff));printf("get all data space len is [%d] \n", ringbuffer_space_len(ringbuff));ringbuffer_destroy(ringbuff);if(data_exec !=NULL){free(data_exec);data_exec = NULL;}//根本不会有write追到read的场景,除非这里的设计做成不是全部取出,或者多线程处理printf("******************* check \n");return 0;
}

3:运行结果

这里我使用的gcc进行编译,没有用makefile

这里是为了符合特定的业务格式,有“FFFF0D0A

”和“0D0AFEFE”进行标识的数据才认为是一个完整的数据。

写这个测试代码主要是为了针对tcp接收缓冲区业务处理考虑的。

hlp@ubuntu:~/220107/0:test_ringbuffer_tcp_Stickybag$ ./ringbuffer
ringbuffer_create size is : 128
ringbuffer isempty [0]
ringbuffer isfull [-1]
ringbuffer used len is [0]
ringbuffer space len is [128]
ringbuffer_create size is : 256
ringbuffer isempty [0]
ringbuffer isfull [-1]
ringbuffer used len is [0]
ringbuffer space len is [256]
set data size is : 30, ringbuff size is 256
ringbuffer isempty [-1]
ringbuffer isfull [-1]
ringbuffer used len is [30]
ringbuffer space len is [226]
get check_end_str is <tail>0D0AFEFE
ringbuff data len is 30
sizeof data_exec is 8
get data from ringbuffer len: [30]
ringbuff get data is :FFFF0D0A<header><tail>0D0AFEFE
ringbuffer isempty [0]
ringbuffer isfull [-1]
ringbuffer used len is [0]
ringbuffer space len is [256]
******************test of more package check***********************
put one data. ringbuffer used len is [30]
put one data.  ringbuffer space len is [226]
put two data. ringbuffer used len is [63]
put two data.  ringbuffer space len is [193]
put three data. ringbuffer used len is [96]
put three data.  ringbuffer space len is [160]
ringbuffer is not empty [-1]
ringbuffer is not full [-1]
get check_end_str is <tail>0D0AFEFE
get ringbuff has data len is 96
get data from ringbuffer len: [96]
ringbuff get data is :FFFF0D0A<header><tail>0D0AFEFEFFFF0D0A<header>111<tail>0D0AFEFEFFFF0D0A<header>222<tail>0D0AFEFE
get all data used len is [0]
get all data space len is [256]
ringbuffer isempty [0]
ringbuffer is not full [-1]
get check_end_str is der>test error
error of ringbuff data
get check_end_str is <tail>0D0AFEFE
get ringbuff has data len is 86
get data from ringbuffer len: [86]
ringbuff get data is :FFFF0D0A<header><tail>0D0AFEFEFFFF0D0A<header>test errorFFFF0D0A<header><tail>0D0AFEFE
get all data used len is [0]
get all data space len is [256]
******************* check

我开始试着积累一些常用代码:自己代码库中备用

我的知识储备更多来自这里,推荐你了解:Linux,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK等技术内容,立即学习

知识巩固源码落实之3:缓冲区ringbuffer相关推荐

  1. 知识巩固源码落实之6:c语言拼接字符串与切割字符串(strsep)代码

    网络数据是以流的形式进行传输的(我们在构造客户端/服务端待发送数据时,肯定有特定的格式). 关于发送一次,一个包的完整性可靠接收(tcp的可靠传输,以及取数据的半包粘包问题)这里不关注,可以参考上文. ...

  2. 知道系统源码/知识问答系统源码/完整PC+手机端带功能强大后台管理系统

    仿百度知道系统源码,知识问答系统源码,带有完整的PC端.手机端界面,功能强大后台管理,非常适用于垂直问答社区类行业网站使用. 阿国简单测试了一下,系统功能比较完善,界面部门需要简单优化一下,整体还是很 ...

  3. 知识付费源码|知识付费网站搭建|知识付费小程序源码

    设计一个在线教育知识付费源码系统(面向对象设计). 解决方案:假设我们想要设计一个基本的内容付费阅读系统并带小程序,提供以下功能: •查找知识数据库并阅读付费内容: •用户成员的创建和扩展: •基于用 ...

  4. java计算机毕业设计知识管理系统源码+数据库+系统+lw文档

    java计算机毕业设计知识管理系统源码+数据库+系统+lw文档 java计算机毕业设计知识管理系统源码+数据库+系统+lw文档 本源码技术栈: 项目架构:B/S架构 开发语言:Java语言 开发软件: ...

  5. JAVA计算机毕业设计基于web的面向公众的食品安全知识系统源码+数据库+系统+lw文档

    JAVA计算机毕业设计基于web的面向公众的食品安全知识系统源码+数据库+系统+lw文档 JAVA计算机毕业设计基于web的面向公众的食品安全知识系统源码+数据库+系统+lw文档 本源码技术栈: 项目 ...

  6. java计算机毕业设计基于web的面向公众的食品安全知识系统源码+数据库+系统+lw文档+mybatis+运行部署

    java计算机毕业设计基于web的面向公众的食品安全知识系统源码+数据库+系统+lw文档+mybatis+运行部署 java计算机毕业设计基于web的面向公众的食品安全知识系统源码+数据库+系统+lw ...

  7. Java版知识付费源码 Spring Cloud+Spring Boot+Mybatis+uniapp+前后端分离实现知识付费平台

    提供职业教育.企业培训.知识付费系统搭建服务.系统功能包含:录播课.直播课.题库.营销.公司组织架构.员工入职培训等. 提供私有化部署,免费售后,专业技术指导,支持PC.APP.H5.小程序多终端同步 ...

  8. 推荐一款知识付费源码支持pc和手机版php+mysql的可以教搭建

    这几天在研究知识付费的源码,也叫内容付费源码,发现网上论坛挺多的,就是能用很少,几经波折,踩了不少坑,刚搭建好一个还不错的源码,推荐给大家. 这套代码属于php+mysql版本,织梦5.7基础上二开的 ...

  9. 知识图谱源码详解【八】__init__.py

    import torch from src.model.DKN.KCNN import KCNN from src.model.DKN.attention import Attention from ...

最新文章

  1. 图书抄袭何时休,技术人的版权在哪里?
  2. 练习题 James and Dominoes
  3. windows系统采用了那种访问控制模型_Linux-3.2 系统与硬件(下)(连载)
  4. Android studio 清除缓存数据的步骤
  5. java的empty_Java Stack empty()方法与示例
  6. CV和NLP中的无监督预训练(生成式BERT/iGPT和判别式SimCLR/SimCSE)
  7. SQL执行效率提升几万倍的操作详解!
  8. JAVA高并发工作笔记0001---高并发编程之ConcurrentLinkedDeque
  9. Qt总结之十一:内存泄漏(汇总)
  10. 揭穿病毒和木马的隐藏手段
  11. Roslyn(CSharpScript).Net脚本编译引擎使用过程内存增涨与稳定的方式
  12. SIM868 GPS模块指令中文解释
  13. 阿里巴巴java工程师应聘条件_【全国】—前端/Java工程师—阿里巴巴(长期招聘)...
  14. Centos桌面版无法打开Chrome浏览器
  15. x265-1.8版本-encoder/dpb.cpp注释
  16. CloudFlare Workers 设置使用自定义域名
  17. 太阳报世界独家爆料:以权谋私、出轨女助理!英国卫生大臣汉考克与女下属办公室热吻摸臀
  18. fastunit中使用MapList一个注意例子
  19. 释放低代码原力,用友YonBuilder助力太湖云打造多云管理平台
  20. 在牛耳培训时的每日一讲ppt

热门文章

  1. 服务器向阿里云转移之容器化1.0.1容器建立
  2. 搭建L2TP-***
  3. 知网下载pdf(再也不想用CAJViewer啦!!!)
  4. MySQL之——mysql5.5 uuid做主键与int做主键的性能实测
  5. 做实景三维项目后的一些感想
  6. Windows服务器如何防止黑客入侵的安全设置
  7. Adobe软件试用下载
  8. 佛罗里达大学计算机工程专业,佛罗里达大学cs专业
  9. pg数据库插件timescale时序库使用记录
  10. OJ1088: 手机短号 (多实例)(C语言)