手写协议报文 c语言手法

鉴于绝大部分文件、网络通信协议、非网络通信协议都有类似的结构{类型,长度,校验,不定长数据,结束标志},再高级点的会包含多个单层TLV,甚至嵌套TLV,状态机流转标志等等。所以编程语言上也需要采用一定的手法。

建立结构

结构体和联合体

例如

//结构体对齐宏
#if defined(__GNUC__)
#define PACKED_STRUCT struct __attribute__((packed))
#endif
#include <stdint.h> //for uint8_t etc.

PACKED_STRUCT Frame {
          uint8_t     HEADER;
          uint8_t     ftype;
          uint16_t    len;
          PACKED_STRUCT Payload payload;
};

struct Data {
  union {
    PACKED_STRUCT Frame frame;
    uint8_t rawdata[];
  };
} data;

使用技巧

这样就可以通过结构体成员名直接操作

  • 写入:data.frame.ftype = 0x89 直接填充。
  • 读取:通过 data.rawdata[i] 直接取到完整的二进制数据。(i表示第i个字节),可以通过 %02X 将该rawdata打印出来

调试/单元测试:可以搞个读写回环,保证数据正确后再接入实际功能代码。

位域

//记得使用packed属性告诉编译器不要瞎优化我的结构体
struct __attribute__((packed))  DataBitm {
	uint8_t flag: 1;
	uint8_t type: 4;
	uint8_t len:  3;
	uint32_t data[];
}

冒号 :1代表该变量只占用1bit。 例如上面代码,type占用了4bit。我们序列化/反序列化的时候就可以直接取到内存映射上的4bit,而无需做位运算。

序列化(serialization)在计算机科学的资料处理中,是指将数据结构或对象状态转换成可取用格式(例如存成文件,存于缓冲,或经由网络中发送),以留待后续在相同或另一台计算机环境中,能恢复原先状态的过程。 依照序列化格式重新获取字节的结果时,可以利用它来产生与原始对象相同语义的副本。反序列化就是它的逆过程。

统一类型

记住这个C99标准库头文件 #include <stdint.h>,里面的类型 uint8_t到uint32_t足够使用,在所有支持C99编译器上均可使用,包括常见的单片机编译平台,不需要自己定义一些奇奇怪怪又不完全通用的什么u8 u32 U32 UINT32这样的类型。

需要注意大小端问题

这个过程需要注意CPU大小端问题,以下是一些转换宏可以用

//大小端转换,其实就是字节换位
#define BIG_TO_LITTLE_ENDIAN_16(x) ((uint16_t)((((x) & 0xFF00) >> 8) | (((x) & 0x00FF) << 8)))
#define BIG_TO_LITTLE_ENDIAN_32(x) ((uint32_t)((((x) & 0xFF000000) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | (((x) & 0x000000FF) << 24)))

C99特性 - 柔性数组

另外还可以使用柔性数组来做不定长的协议报文,关键词: C99 柔性数组,但柔性数组只能用在结构体的尾部,所以如果有帧尾,一般不把帧尾放入结构体里,而是在函数里手动填充。

然后在填充报文的函数里再做switch分支即可完成协议的子类解析。
复制报文数据到发送区的时候一般使用 memcpy(dst,src,size);

状态机流转

最好画一个状态机的图便于分析和修改,这个有很多画流程图的软件都可以做到。

参考案例

接下来我们观赏一段英特尔处理媒体流协议的代码,是RTP协议下的子类。
GITHUB项目地址:https://github.com/OpenVisualCloud/Media-Transport-Library

数据填充

image

告诉编译器不优化结构体

attribute ((packed)) 的作用就是告诉编译器取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐,是GCC特有的语法。当然其他编译器也有类似的属性名

image

结构体和联合体。

image

posted @ 2024-04-23 10:52  蓝天上的云℡  阅读(71)  评论(0编辑  收藏  举报