当前位置:网站首页>Knowledge consolidation source code implementation 3: buffer ringbuffer

Knowledge consolidation source code implementation 3: buffer ringbuffer

2022-07-06 04:18:00 yun6853992

1: Background introduction :

In daily business development , There are many business scenarios using buffers for temporary storage , Such as tcp The bottom layer of each connection maintains a send buffer and a receive buffer .

Achieve one ringbuffer, Make code backup .( You can consider how to treat ringbuffer To expand ?)

// Realization ringbuffer, In fact, it is to apply for a piece of memory , Manage the positions of inserting data and extracting data respectively 
typedef struct RINGBUFF_T{
    
	void * data;
	unsigned int size;
	unsigned int read_pos;   // Data start position 
	unsigned int write_pos;  // Data termination location 
}ringbuffer_t;

2: Test code :

The code here is for me to test , Achieve one ringbuffer Conduct management .

Only the logical implementation of single thread is considered here , Multithreading needs to be adapted ...

Here, when fetching data , Have a certain design , Consider taking the data of a package ( You can adjust it by yourself ).

2.1:my_ringbuffer.h

#ifndef __RINGBUFFER_H_
#define __RINGBUFFER_H_

typedef struct RINGBUFF_T{
    
	void * data;
	unsigned int size;
	unsigned int read_pos;   // Data start position 
	unsigned int write_pos;  // Data termination location 
}ringbuffer_t;

// establish ringbuffer
ringbuffer_t * ringbuffer_create(unsigned int size);
// The destruction ringbuffer
void ringbuffer_destroy(ringbuffer_t * ring_buffer);

// Go to ringbuffer Data stored in   write in 
int ringbuffer_put(ringbuffer_t * ring_buffer, const char* buffer, unsigned int len);
// Judge whether it is complete data   And then deal with it 
int ringbuffer_get_len(ringbuffer_t *ring_buffer);
// rely on ringbuffer_get_len  Return value request memory , Take out ring_buffer Data in 
int ringbuffer_get(ringbuffer_t * ring_buffer, char * buffer, unsigned int len);

// Basic interface   Basically no external , But there are uses inside the function 
// Reset buffer 
void ringbuffer_reset(ringbuffer_t * ring_buffer);
//ringbuffer The amount of memory space that has been used 
int ringbuffer_use_len(ringbuffer_t * ring_buffer);
//ringbuffer The size of unused memory 
int ringbuffer_space_len(ringbuffer_t * ring_buffer);

// Basic empty and full interfaces 
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;
}

// establish ringbuffer 
ringbuffer_t * ringbuffer_create(unsigned int size)
{
    
	// Verify the input parameters   And is 2 To the power of 
	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;
}

// The destruction 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;
	}
}

// Go to ringbuffer Data stored in   write in 
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)))
	{
    
		// Copy 
		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;
}

// Judge whether it is complete data   And then deal with it 
int ringbuffer_get_len(ringbuffer_t *ring_buffer)
{
    
	// Yes ringbuffer Judge and analyze the data in   If it is complete data   Then extract 
	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;
	}
	// Determine whether it is a terminated field 
	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);
}

// from ringbuffer Extract data for processing ,  Determine whether the received character is a terminator , You can deal with it 
// Reset after getting data ringbuffer The location of   Read 
int ringbuffer_get(ringbuffer_t * ring_buffer, char * buffer, unsigned int len)
{
    
	// This is based on ringbuffer_get_len  On the basis of , Pass in parameters , Take out the data 
	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;
}

// Directly from socket Middle reading data is put into ringbuffer You can also do so. 
int ringbuffer_get_from_dev()
{
    
	return 0;
}
// Directly from ringbuffer To extract data from socket Send 
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:  Yes ringbuffer Do a simple test of the package  data: 2022/02/10 author: hlp ************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "tcp_ringbuffer.h"

int main()
{
    
	// Apply for one 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);
	// Judge the basic conditions 
	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);

	// to ringbuff Insert a certain amount of data in to view the relevant basic information 
	ringbuff = ringbuffer_create(129);
	const char* str_data = "FFFF0D0A<header><tail>0D0AFEFE";
	// to ringbuffer Insert certain data into , Get to view 
	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";
	// Try inserting multiple data   Can you take it out ?
	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;
	}
	// There won't be write Catch up with read Scene , Unless the design here is not all taken out , Or multithreading 
	printf("******************* check \n");

	return 0;
}

3: Running results

I used it here gcc Compile , of no avail makefile

This is to conform to the specific business format , Yes “FFFF0D0A

” and “0D0AFEFE” The identified data is considered to be a complete data .

This test code is mainly written for tcp Receive buffer business processing considerations .

[email protected]:~/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

I started trying to accumulate some common code : Spare in your own code base

More of my knowledge comes from here , I recommend you understand :Linux,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK, Streaming media ,CDN,P2P,K8S,Docker,TCP/IP, coroutines ,DPDK Etc , Learn now

原网站

版权声明
本文为[yun6853992]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/02/202202132234018682.html