在linux应用程序开发过程中,通常会涉及到从高速数据接口(如网络socket、消息队列)接收数据并处理数据内容,但由于高速数据接口一般底层包含协议,如网络接口采用TCP/IP协议,采用帧作为数据传输的最小单位。为了linux应用程序正确读取高速数据接口数据、又不影响到系统其他接口功能、并保证待读取高速数据接口数据不丢失,一般会在应用程序添加二维循环队列作为缓存使用。从高速数据接口接收数据帧首先存入二维循环队列,待需要处理时再从循环队列中按数据帧读取数据。
本节介绍一种C语言设计的二维循环队列,该队列主要适用于网络通讯(含10/100/1000Mbps)TCP/UDP数据接收缓存、消息队列等以数据帧为最小单位的高速数据接口的数据缓存。
1、首先编写二维队列的头文件app_queue.h,头文件主要包括二维队列结构体的定义、参数宏定义等内容。
#ifndef SRC_APP_QUEUE_H_
#define SRC_APP_QUEUE_H_
#include <pthread.h>
#define MAX_MESSAGE_FRAME_NUM (2*1024) //最大帧数量 2K 最大共16MB缓存
#define MAX_FRAME_SIZE (8*1024) //最大帧大小 8K
typedef struct Message_Queue
{
unsigned char buffer[MAX_MESSAGE_FRAME_NUM][MAX_FRAME_SIZE]; //队列缓存指针
unsigned int sizetab[MAX_MESSAGE_FRAME_NUM]; //每个队列中数据大小
// unsigned int max_size; //队列最大空间
unsigned int read_index; //读数据位置
unsigned int write_index; //写数据位置
unsigned int count; //队列数据量
pthread_mutex_t mutex;
}message_queue;
extern message_queue udpRevDataQueue;
int read_MessageQueue(message_queue *src_queue, unsigned char *data);
int write_MessageQueue(message_queue *dst_queue, unsigned char *data,unsigned int length);
void init_Queue_All(void);
#endif
2、然后编写二维队列的源文件app_queue.c,源文件主要包括二维队列结构体初始化、二维队列读写函数的实现。
#include <stdio.h>
#include <string.h>
#include "app_queue.h"
message_queue udpRevDataQueue; //接收udp命令队列
/******************************************************************************
*FUNCATION NAME : int write_MessageQueue(message_queue *dst_queue, unsigned char *data,unsigned int length)
*CREATE DATE : 2022-11-02
*CREATE BY : LSL
*FUNCTION : 二维队列写一帧数据,最大帧数据为2048字节
*MODIFY DATE :
*INPUT : message_queue *dst_queue 待写入的消息队列指针
unsigned char *data 待写入的数据指针
unsigned int length 待写入的帧数据字节数
*OUTPUT :
*RETURN : 0 成功 -1失败
*OTHERS :
******************************************************************************/
int write_MessageQueue(message_queue *dst_queue, unsigned char *data,unsigned int length)
{
int rst = -1;
if(NULL == dst_queue)
{
printf("write_message_queue err!\n");
return rst;
}
if(dst_queue->count >= MAX_MESSAGE_FRAME_NUM) //队列
{
printf("write_message_queue err 2,dst_queue->count=%d,max_size=%d\n",dst_queue->count,MAX_MESSAGE_FRAME_NUM);
return rst;
}
pthread_mutex_lock(&dst_queue->mutex);
memcpy((dst_queue->buffer[dst_queue->write_index]),data,length);//拷贝数据帧到队列中
//*(dst_queue->buffer+dst_queue->write_index) = *data;
dst_queue->sizetab[dst_queue->write_index]=length;
dst_queue->write_index++;
dst_queue->count++;
if(dst_queue->write_index >= MAX_MESSAGE_FRAME_NUM)
{
dst_queue->write_index = 0;
}
pthread_mutex_unlock(&dst_queue->mutex);
rst = length;
return rst;
}
/******************************************************************************
*FUNCATION NAME : int read_MessageQueue(message_queue *src_queue, unsigned char *data)
*CREATE DATE : 2022-11-02
*CREATE BY : LSL
*FUNCTION : 二维队列读一帧数据,最大帧数据为2048字节
*MODIFY DATE :
*INPUT : message_queue *dst_queue 待读取的消息队列指针
unsigned char *data 待读取的数据指针
*OUTPUT :
*RETURN : 读取到帧数据字节数;小于0则读取失败
*OTHERS :
******************************************************************************/
int read_MessageQueue(message_queue *src_queue, unsigned char *data)
{
int rst = -1;
int data_len;
if(NULL==src_queue || NULL==data)
{
printf("read_MessageQueue Error!\n");
return rst;
}
if(src_queue->count == 0)
{
return rst;
}
pthread_mutex_lock(&src_queue->mutex);
data_len=src_queue->sizetab[src_queue->read_index];
memcpy(data,src_queue->buffer[src_queue->read_index],data_len);//从队列中取出数据
//*data = src_queue->buffer[src_queue->read_index];
memset(src_queue->buffer[src_queue->read_index],0,data_len);
src_queue->sizetab[src_queue->read_index]=0x00;//读取数据后,队列缓存清零
src_queue->read_index++;
src_queue->count--;
if(src_queue->read_index >= MAX_MESSAGE_FRAME_NUM)
{
src_queue->read_index = 0;
}
//rst = 0;
pthread_mutex_unlock(&src_queue->mutex);
return data_len;
}
/******************************************************************************
*FUNCATION NAME : void init_MessageQueue(message_queue *src_queue)
*CREATE DATE : 2022-11-02
*CREATE BY : LSL
*FUNCTION : 初始化消息队列(二维队列)
*MODIFY DATE :
*INPUT :
*OUTPUT :
*RETURN :
*OTHERS :
******************************************************************************/
void init_MessageQueue(message_queue *src_queue)
{
src_queue->buffer[0][0] =0 ;
src_queue->count = 0;
src_queue->read_index = 0;
//src_queue->recv_time = 0;
src_queue->write_index = 0;
}
/******************************************************************************
*FUNCATION NAME : void init_queue_all(void)
*CREATE DATE : 2021-11-02
*CREATE BY : LSL
*FUNCTION : 初始化队列配置
*MODIFY DATE :
*INPUT :
*OUTPUT :
*RETURN :
*OTHERS :
******************************************************************************/
void init_Queue_All(void)
{
init_MessageQueue((message_queue *)&udpRevDataQueue);//初始化二维UDP接收队列
}
3、测试代码源文件文件如下所示:main.c,测试函数主要实现向二维队列写入多个递增数的数据帧,然后从二维队列读取数据帧,并对数据帧的内容进行判断,检验二维队列的工作有效性。

4、Makefile文件为:

5、编译脚本build_myapp.sh为如下所示

6、给编译脚本添加可执行权限,运行编译脚本生成可执行程序framemyapp:

7、运行framemyapp的可执行程序,进行队列写入和队列读取数据的测试结果如下,下图为测试结果部分截图,未出现数据校验出错,说明二维循环队列工作正常:

本文含有隐藏内容,请 开通VIP 后查看