C语言-策略模式详解与实践 - 多协议解析器实现
1. 什么是策略模式?
策略模式定义了一系列算法,将每个算法封装起来,并使它们可以互相替换。策略模式让算法独立于使用它的客户端而变化。
2. 为什么需要策略模式?
- 支持多种协议解析
- 动态切换解析策略
- 易于扩展新协议
- 解耦协议解析与业务逻辑
- 简化协议处理流程
3. 实际应用场景
- 串口多协议解析
- 网络协议处理
- 数据格式转换
- 通信协议适配
- 设备驱动开发
4. 代码实现
4.1 UML 关系图
4.2 头文件 (protocol_parser.h)
#ifndef PROTOCOL_PARSER_H
#define PROTOCOL_PARSER_H
#include <stdint.h>
#include <stdbool.h>
// 协议类型
typedef enum {
PROTOCOL_MODBUS = 0,
PROTOCOL_CUSTOM,
PROTOCOL_DEBUG,
PROTOCOL_MAX
} ProtocolType;
// 解析结果
typedef struct {
uint8_t cmd; // 命令码
uint8_t* data; // 数据
uint16_t length; // 数据长度
bool success; // 是否成功
char error[64]; // 错误信息
} ParseResult;
// 解析器接口
typedef bool (*ValidateFunc)(const uint8_t* data, uint16_t length);
typedef bool (*ParseFunc)(const uint8_t* data, uint16_t length, ParseResult* result);
// 协议解析器
typedef struct {
ValidateFunc validate; // 数据校验
ParseFunc parse; // 数据解析
const char* name; // 协议名称
} ProtocolParser;
// 创建解析器
ProtocolParser* create_parser(ProtocolType type);
// 销毁解析器
void destroy_parser(ProtocolParser* parser);
// 解析数据
bool parse_protocol_data(ProtocolParser* parser,
const uint8_t* data,
uint16_t length,
ParseResult* result);
#endif // PROTOCOL_PARSER_H
4.3 实现文件 (protocol_parser.c)
#include "protocol_parser.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// Modbus协议解析
static bool modbus_validate(const uint8_t* data, uint16_t length) {
if (length < 4) return false;
// 简单的CRC校验
uint8_t sum = 0;
for (uint16_t i = 0; i < length - 1; i++) {
sum += data[i];
}
return (sum == data[length - 1]);
}
static bool modbus_parse(const uint8_t* data, uint16_t length, ParseResult* result) {
if (!modbus_validate(data, length)) {
strcpy(result->error, "Modbus校验失败");
result->success = false;
return false;
}
result->cmd = data[1];
result->data = (uint8_t*)malloc(length - 3);
memcpy(result->data, &data[2], length - 3);
result->length = length - 3;
result->success = true;
return true;
}
// 自定义协议解析
static bool custom_validate(const uint8_t* data, uint16_t length) {
if (length < 5) return false;
return (data[0] == 0xAA && data[length-1] == 0x55);
}
static bool custom_parse(const uint8_t* data, uint16_t length, ParseResult* result) {
if (!custom_validate(data, length)) {
strcpy(result->error, "自定义协议校验失败");
result->success = false;
return false;
}
result->cmd = data[1];
result->data = (uint8_t*)malloc(length - 4);
memcpy(result->data, &data[2], length - 4);
result->length = length - 4;
result->success = true;
return true;
}
// 调试协议解析
static bool debug_validate(const uint8_t* data, uint16_t length) {
return (length > 0 && data[0] == 0xDD);
}
static bool debug_parse(const uint8_t* data, uint16_t length, ParseResult* result) {
if (!debug_validate(data, length)) {
strcpy(result->error, "调试协议校验失败");
result->success = false;
return false;
}
result->cmd = 0xFF;
result->data = (uint8_t*)malloc(length - 1);
memcpy(result->data, &data[1], length - 1);
result->length = length - 1;
result->success = true;
return true;
}
// 协议解析器表
static const ProtocolParser parsers[] = {
{modbus_validate, modbus_parse, "Modbus"},
{custom_validate, custom_parse, "Custom"},
{debug_validate, debug_parse, "Debug"}
};
ProtocolParser* create_parser(ProtocolType type) {
if (type >= PROTOCOL_MAX) return NULL;
ProtocolParser* parser = (ProtocolParser*)malloc(sizeof(ProtocolParser));
memcpy(parser, &parsers[type], sizeof(ProtocolParser));
return parser;
}
void destroy_parser(ProtocolParser* parser) {
free(parser);
}
bool parse_protocol_data(ProtocolParser* parser,
const uint8_t* data,
uint16_t length,
ParseResult* result) {
printf("使用%s协议解析数据\n", parser->name);
return parser->parse(data, length, result);
}
4.4 使用示例 (main.c)
#include "protocol_parser.h"
#include <stdio.h>
void print_result(const ParseResult* result) {
if (result->success) {
printf("解析成功:\n");
printf("命令码: 0x%02X\n", result->cmd);
printf("数据长度: %d\n", result->length);
printf("数据内容: ");
for (int i = 0; i < result->length; i++) {
printf("%02X ", result->data[i]);
}
printf("\n");
} else {
printf("解析失败: %s\n", result->error);
}
}
void cleanup_result(ParseResult* result) {
if (result->data) {
free(result->data);
result->data = NULL;
}
}
int main() {
// Modbus协议测试
printf("=== Modbus协议测试 ===\n");
uint8_t modbus_data[] = {0x01, 0x03, 0x11, 0x22, 0x37};
ProtocolParser* modbus_parser = create_parser(PROTOCOL_MODBUS);
ParseResult modbus_result = {0};
parse_protocol_data(modbus_parser, modbus_data, sizeof(modbus_data), &modbus_result);
print_result(&modbus_result);
cleanup_result(&modbus_result);
// 自定义协议测试
printf("\n=== 自定义协议测试 ===\n");
uint8_t custom_data[] = {0xAA, 0x01, 0x33, 0x44, 0x55};
ProtocolParser* custom_parser = create_parser(PROTOCOL_CUSTOM);
ParseResult custom_result = {0};
parse_protocol_data(custom_parser, custom_data, sizeof(custom_data), &custom_result);
print_result(&custom_result);
cleanup_result(&custom_result);
// 调试协议测试
printf("\n=== 调试协议测试 ===\n");
uint8_t debug_data[] = {0xDD, 0x55, 0x66, 0x77};
ProtocolParser* debug_parser = create_parser(PROTOCOL_DEBUG);
ParseResult debug_result = {0};
parse_protocol_data(debug_parser, debug_data, sizeof(debug_data), &debug_result);
print_result(&debug_result);
cleanup_result(&debug_result);
// 清理资源
destroy_parser(modbus_parser);
destroy_parser(custom_parser);
destroy_parser(debug_parser);
return 0;
}
5. 代码分析
5.1 关键设计点
- 统一的解析器接口
- 策略的动态选择
- 完整的错误处理
- 资源管理安全
5.2 实现特点
- 函数指针实现多态
- 协议解析解耦
- 内存管理完善
- 扩展性良好
6. 编译和运行
gcc -c protocol_parser.c -o protocol_parser.o
gcc -c main.c -o main.o
gcc protocol_parser.o main.o -o protocol_demo
7. 注意事项
- 协议数据校验
- 内存管理安全
- 错误处理完整
- 协议兼容性
8. 改进建议
- 添加协议版本支持
- 实现协议转换功能
- 添加协议缓存机制
- 支持协议分片处理
9. 总结
策略模式通过封装不同的协议解析算法,实现了协议解析的灵活切换和扩展。这种模式特别适合处理多协议解析的场景。
参考资料
- 《设计模式:可复用面向对象软件的基础》
- 《C语言程序设计》
- 《通信协议设计》