使用数组重构责任链实现通信协议解析

在嵌入式软件中,使用数组实现责任链模式是一种高效且易于维护的设计方法。相比链表,数组实现具有内存连续、访问速度快、代码简洁等优势,非常适合资源受限且对实时性要求高的嵌入式环境

为什么在嵌入式中用数组实现责任链?

1.内存连续,缓存友好:数组在内存中是连续存储的,遍历时CPU缓存命中率高,执行效率优于链表。

2.无需动态内存分配:可以预先定义固定大小的数组,避免使用 malloc/free,降低内存碎片风险。

3.代码简洁,易于调试:使用 for 循环遍历,逻辑清晰,调试时更容易追踪执行流程。

4.适合静态配置:嵌入式系统通常在编译时确定功能模块,数组非常适合这种"静态组装、动态执行"的模式。

以串口协议解析为例,实现一个基于数组的责任链
第一步:定义统一的处理器接口

c 复制代码
// protocol_handler.h
#ifndef PROTOCOL_HANDLER_H
#define PROTOCOL_HANDLER_H

#include <stdint.h>
#include <stdbool.h>

// 处理结果
typedef enum {
    HANDLER_OK,    // 成功处理,链条终止
    HANDLER_PASS,  // 无法处理,继续下一个
    HANDLER_ERROR  // 发生错误,终止链条
} HandlerResult;

// 处理器函数类型
typedef HandlerResult (*HandlerFunc)(uint8_t* data, int len);

// 责任链最大长度
#define MAX_HANDLERS 8

// 责任链结构体
typedef struct {
    HandlerFunc handlers[MAX_HANDLERS];  // 处理器函数数组
    int count;                           // 当前处理器数量
} ProtocolChain;

// 初始化责任链
void chain_init(ProtocolChain* chain);

// 添加处理器
bool chain_add_handler(ProtocolChain* chain, HandlerFunc handler);

// 执行责任链
HandlerResult chain_execute(ProtocolChain* chain, uint8_t* data, int len);

#endif

第二步:实现责任链核心逻辑

c 复制代码
// protocol_handler.c
#include "protocol_handler.h"
#include <string.h>

// 初始化
void chain_init(ProtocolChain* chain) {
    memset(chain->handlers, 0, sizeof(chain->handlers));
    chain->count = 0;
}

// 添加处理器
bool chain_add_handler(ProtocolChain* chain, HandlerFunc handler) {
    if (chain->count >= MAX_HANDLERS) {
        return false; // 数组已满
    }
    chain->handlers[chain->count++] = handler;
    return true;
}

// 执行责任链
HandlerResult chain_execute(ProtocolChain* chain, uint8_t* data, int len) {
    for (int i = 0; i < chain->count; i++) {
        HandlerResult result = chain->handlers[i](data, len);
        if (result != HANDLER_PASS) {
            return result; // OK 或 ERROR 都终止链条
        }
    }
    return HANDLER_PASS; // 所有处理器都未处理
}

第三步:实现具体协议处理器

c 复制代码
// modbus_handler.c
#include "protocol_handler.h"
#include <stdio.h>

// 简单的CRC校验函数(示例)
static bool check_crc(uint8_t* data, int len) {
    // 实际项目中应实现真实CRC算法
    return len >= 4; // 简化判断
}

// Modbus协议处理器
HandlerResult handle_modbus(uint8_t* data, int len) {
    if (len >= 4 && data == 0x01 && check_crc(data, len)) {
        printf("Modbus frame received: ");
        for (int i = 0; i < len; i++) {
            printf("%02X ", data[i]);
        }
        printf("\n");
        // 执行Modbus命令解析...
        return HANDLER_OK;
    }
    return HANDLER_PASS; // 不是Modbus帧,交给下一个
}
c 复制代码
// custom_handler.c
#include "protocol_handler.h"
#include <stdio.h>

// 自定义协议处理器
HandlerResult handle_custom(uint8_t* data, int len) {
    if (len >= 3 && data == 0xAA) {
        printf("Custom protocol: 0x%02X 0x%02X 0x%02X\n", 
               data, data, data);
        // 处理自定义协议...
        return HANDLER_OK;
    }
    return HANDLER_PASS;
}
```<websource>source_group_web_1</websource>

#### 第四步:组装和使用责任链

```c
// main.c
#include "protocol_handler.h"
#include <stdio.h>

// 外部声明处理器
extern HandlerResult handle_modbus(uint8_t*, int);
extern HandlerResult handle_custom(uint8_t*, int);

int main() {
    ProtocolChain chain;
    
    // 1. 初始化责任链
    chain_init(&chain);
    
    // 2. 静态组装责任链(编译时确定顺序)
    chain_add_handler(&chain, handle_custom);   // 先检查自定义协议
    chain_add_handler(&chain, handle_modbus);   // 再检查Modbus
    
    // 3. 模拟串口接收数据
    uint8_t frame1[] = {0xAA, 0x01, 0x02};           // 自定义协议
    uint8_t frame2[] = {0x01, 0x03, 0x00, 0x00};     // Modbus协议
    uint8_t frame3[] = {0xFF, 0xFF, 0xFF};           // 未知协议
    
    printf("--- Processing Frame 1 ---\n");
    chain_execute(&chain, frame1, sizeof(frame1));
    
    printf("\n--- Processing Frame 2 ---\n");
    chain_execute(&chain, frame2, sizeof(frame2));
    
    printf("\n--- Processing Frame 3 ---\n");
    chain_execute(&chain, frame3, sizeof(frame3));
    
    return 0;
}

数组实现 vs 链表实现

特性 数组实现 链表实现
内存使用 静态分配,无碎片 动态分配,可能碎片化
执行效率 高(缓存友好) 较低(指针跳转)
代码复杂度 简单(for循环) 复杂(指针管理)
调试难度 容易(索引清晰) 较难(指针追踪)
扩展性 固定大小,编译时确定 运行时动态添加
适用场景 协议解析、过滤器、校验链 动态审批流、插件系统
相关推荐
QXWZ_IA2 小时前
边坡监测预算有限时的建设顺序:虚拟基准站与成本账
网络·数据库
聪明蛋子哟5 小时前
大模型应用“最后一公里”:从Prompt工程到MCP协议,如何实现跨系统的高可用集成?
网络·prompt
La Pulga5 小时前
【FreeRTOS源码学习笔记】链表的实现
数据结构·笔记·stm32·mcu·链表·嵌入式·freertos
科创致远6 小时前
ESOP 电子作业指导书 WiFi 网络应用实测报告
运维·服务器·网络
承渊政道6 小时前
Linux网络学习【从NAT与代理服务理解网络转发、探索内网穿透原理、再到认识DNS与ICMP、最后动手部署并测试内网穿透】
linux·网络·学习·内网穿透·dns·nat
最强小杰6 小时前
minimax-m3 突然报 HTTP 529 怎么办?连续重试为何更难恢复,退避时间该怎么算?
网络·网络协议·http·ai
程序员清风6 小时前
AI 编程助手的权限边界:文件、命令、密钥与人工确认
运维·服务器·网络
别讲概念7 小时前
JavaEE(5)网络原理初识
网络·java-ee·智能路由器
爱吃香菜的初学者7 小时前
十九.Linux——TCP协议(1)
linux·网络·tcp/ip
好啊好啊郝!8 小时前
计算机网络最基础知识点
服务器·网络·计算机网络