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等技术内容,立即学习