2024年Go最新可参考的通信数据接收解析方法_解析通信对数据,最新阿里+头条+腾讯大厂Golang笔试真题

img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

flag++;
else
flag = 0;
}
else if(flag == 3)
{
if(tempData == 0x80)
flag++;
else
flag = 0;
}
else if(flag == 4)
{
if(tempData == 0x02)
flag++;
else
flag = 0;
}
else if(flag == 5 || flag == 6 || flag == 7)
{
data[flag-5] = tempData;
flag = (flag == 7) ? 0 : flag+1;
}


使用上述方法是最容易想到的也是最简单的方法了,百度了一下基本上也都是使用类似的方法进行数据解析,但是使用这种方法有如下几个缺点:1、 大量使用了判断,容易导致出现逻辑混乱。2、 代码重复率高,抽象程度低。从上述代码可以看到一大堆代码仅仅是判断的数据不同,其他代码都完全一致。3、 代码可复用性差。写好的代码无法用在其他类似的外设上,如果有多个外设就需要编写多份类似的代码。4、 可扩展性低。如果外设还有一个数据校验尾需要校验或者数据校验头发生改变,就需要再次写多个判断重新用于校验,无法在原有的代码上进行扩展。5、 容易出现误判 。对此,这里提出了一种新的解决方案,可以通用与所有类似的数据解析,原理如下:使用一个固定容量的队列用来缓存接收到的数据,队列容量等于一帧数据的大小,每来一个数据就将数据往队列里面加,当完整接收到一帧数据时此时队列中的全部数据也就是一帧完整的数据,因此只需要判断队列是否是数据校验头,队列尾是否是数据校验尾就可以得知当前是否已经接收到了一帧完整的数据,然后在将数据从队列中取出即可。原理图如下:每来一个数据就往队列里面加:


![图片](https://img-blog.csdnimg.cn/img_convert/263f1e4d4957f5a98f356892d4041380.png)


当接收到一帧完整数据时队列头和数据校验头重合:


![图片](https://img-blog.csdnimg.cn/img_convert/3a64bee2de9624a96eb6016792849716.png)


此时只需要从队列中取出有效数据即可。如果有数据尾校验,仅仅只需要添加一个校验尾即可,如下图所示:


![图片](https://img-blog.csdnimg.cn/img_convert/e0200c9fdf214641cdfd137abef379ff.png)


好,分析结束,开始编码。首先需要一个队列,为了保证通用性,队列底层使用类似于双向链表的实现(当然也可以使用数组实现),需要封装的结构有队列容量、队列大小、队头节点和队尾节点,需要实现的操作有队列初始化、数据入队、数据出队、清空队列和释放队列,具体代码如下:



/* queue.h */

#ifndef _QUEUE_H_
#define _QUEUE_H_

#ifndef NULL
#define NULL ((void *)0)
#endif

typedef unsigned char uint8;

/* 队列节点 */
typedef struct Node
{
uint8 data;
struct Node *pre_node;
struct Node *next_node;
} Node;

/* 队列结构 */
typedef struct Queue
{
uint8 capacity; // 队列总容量
uint8 size; // 当前队列大小
Node *front; // 队列头节点
Node *back; // 队列尾节点
} Queue;

/* 初始化一个队列 */
Queue *init_queue(uint8 _capacity);
/* 数据入队 */
uint8 en_queue(Queue *_queue, uint8 _data);
/* 数据出队 */
uint8 de_queue(Queue *_queue);
/* 清空队列 */
void clear_queue(Queue *_queue);
/* 释放队列 */
void release_queue(Queue *_queue);

#endif
/* queue.c */

#include <stdlib.h>
#include “parser.h”

/**
* 初始化一个队列
*
* @_capacity: 队列总容量
*/
Queue *init_queue(uint8 _capacity)
{
Queue *queue = (Queue *)malloc(sizeof(Queue));
queue->capacity = _capacity;
queue->size = 0;
return queue;
}

/**
* 数据入队
*
* @_queue: 队列
* @_data: 数据
**/
uint8 en_queue(Queue *_queue, uint8 _data)
{
if(_queue->size < _queue->capacity)
{
Node *node = (Node *)malloc(sizeof(Node));
node->data = _data;
node->next_node = NULL;

    if(_queue->size == 0)
    {
        node->pre_node = NULL;
        _queue->back = node;
        _queue->front = _queue->back;
    }
    else
    {
        node->pre_node = _queue->back;

        _queue->back->next_node = node;
        _queue->back = _queue->back->next_node;
    }

_queue->size++;
}
else
{
Node *temp_node = _queue->front->next_node;
_queue->front->pre_node = _queue->back;
_queue->back->next_node = _queue->front;
_queue->back = _queue->back->next_node;
_queue->back->data = _data;
_queue->back->next_node = NULL;
_queue->front = temp_node;
}
return _queue->size-1;
}

/**
* 数据出队
*
* @_queue: 队列
*
* @return: 出队的数据
*/
uint8 de_queue(Queue *_queue)
{
uint8 old_data = 0;

if(_queue->size > 0)
{
    old_data = _queue->front->data;
    if(_queue->size == 1)
    {
        free(_queue->front);
        _queue->front = NULL;
        _queue->back = NULL;
    }
    else
    {
        _queue->front = _queue->front->next_node;
        free(_queue->front->pre_node);
        _queue->front->pre_node = NULL;
    }
    _queue->size--;
}
return old_data;

}

/**
* 清空队列
*
* @_queue: 队列
*/
void clear_queue(Queue *_queue)
{
while(_queue->size > 0)
{
de_queue(_queue);
}
}

/**
* 释放队列
*
* @_queue: 队列
*/
void release_queue(Queue *_queue)
{
clear_queue(_queue);
free(_queue);
_queue = NULL;
}


其次是解析器,需要封装的结构有解析数据队列、数据校验头、数据校验尾、解析结果以及指向解析结果的指针,需要实现的操作有解析器初始化、添加数据解析、获取解析结果、重置解析器和释放解析器,具体代码如下:



/* parser.h */

#ifndef _PARSER_H_
#define _PARSER_H_

#include “queue.h”

typedef enum
{
RESULT_FALSE,
RESULT_TRUE
} ParserResult;

/* 解析器结构 */
typedef struct DataParser
{
Queue *parser_queue; // 数据解析队列
Node *resule_pointer; // 解析结果数据指针
uint8 *data_header; // 数据校验头指针
uint8 header_size; // 数据校验头大小
uint8 *data_footer; // 数据校验尾指针
uint8 footer_size; // 数据校验尾大小
uint8 result_size; // 解析数据大小
ParserResult parserResult; // 解析结果
} DataParser;

/* 初始化一个解析器 */
DataParser *parser_init(uint8 *_data_header, uint8 _header_size, uint8 *_data_footer, uint8 _foot_size, uint8 _data_frame_size);
/* 将数据添加到解析器中进行解析 */
ParserResult parser_put_data(DataParser *_parser, uint8 _data);
/* 解析成功后从解析器中取出解析结果 */
int parser_get_data(DataParser *_parser, uint8 _index);
/* 重置解析器 */
void parser_reset(DataParser *_parser);
/* 释放解析器 */
void parser_release(DataParser *_parser);

#endif
/* parser.c */

#include <stdlib.h>
#include “parser.h”

/**
* 初始化一个解析器
*
* @_data_header: 数据头指针
* @_header_size: 数据头大小
* @_data_footer: 数据尾指针
* @_foot_size: 数据尾大小
* @_data_frame_size: 一帧完整数据的大小
*
* @return: 解析器
*/
DataParser *parser_init(uint8 *_data_header, uint8 _header_size, uint8 *_data_footer, uint8 _foot_size, uint8 _data_frame_size)
{
if((_header_size+_foot_size) > _data_frame_size || (_header_size+_foot_size) == 0)
return NULL;

DataParser \*parser = (DataParser \*)malloc(sizeof(DataParser));
parser->parser_queue = init\_queue(_data_frame_size);
parser->resule_pointer = NULL;
parser->data_header = _data_header;
parser->header_size = _header_size;

parser->data_footer = _data_footer;
parser->footer_size = _foot_size;
parser->result_size = _data_frame_size - parser->header_size - parser->footer_size;
parser->parserResult = RESULT_FALSE;

while(_data_frame_size-- > 0)
{
    en\_queue(parser->parser_queue, 0);
}

return parser;

}

/**
* 将数据添加到解析器中进行解析
*
* @_parser: 解析器
* @_data: 要解析的数据
*
* @return: 当前解析结果,返回 RESULT_TRUE 代表成功解析出一帧数据
*/
ParserResult parser_put_data(DataParser *_parser, uint8 _data)
{
uint8 i;
Node *node;

if(_parser == NULL)
return RESULT_FALSE;

en\_queue(_parser->parser_queue, _data);

/* 校验数据尾 */
node = _parser->parser_queue->back;
for(i = _parser->footer_size; i > 0; i–)
{
if(node->data != _parser->data_footer[i-1])
goto DATA_FRAME_FALSE;
node = node->pre_node;
}

img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

[外链图片转存中…(img-2pLy6C9E-1715646042331)]
[外链图片转存中…(img-Pg9gRg6M-1715646042332)]
[外链图片转存中…(img-E8WzCtN0-1715646042332)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

  • 18
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值