QAMF 是 QDAC 项目中的一个新成员,用来支持 AMF 格式的解析。受限于作者手头的 AMF 资料的欠缺,可能有些实现并不一定 100% 正确,如果大家在使用过程中发现什么问题,请提供一个具体的详细测试用例,并请说明:
1、原始需要解析或生成的数据包;
2、重现问题的测试程序
3、问题的具体描述
再次感谢大家对 QDAC 项目的支持,现在说明一下 QAMF 的基本用法:
1、解析一个带有协议头部的 AMF 格式数据流:
这种格式的数据流,带有完整的 AMF 协议头部,而不是单纯的数据内容。QAMF 提供了以下几种方式来完成解析:
- Parse/TryParse
TryParse 会尝试解析内存中的协议数据,如果无法正确解析,则返回 False,解析成功,则返回 True。而 Parse 则在解析失败时抛出异常。请根据实际需要选择。 - LoadFromStream/LoadFromFile
直接从流或文件中解析 AMF 数据。如果解析失败,则抛出异常。
这种格式的数据流的格式,包含三个组成部分:
- 文件头
文件头包含版本号:两个字节,代表协议的版本 00 03 代表是 AMF3, 00 00 代表 AMF 0。但实际上这个版本标记意义不大。因为默认的存贮是以AMF 0 数据开始,然后根据需要临时切换到 AMF3 格式的。 - 头部列表
首先是一个 BE 编码的16位无符号整数,来标记头部的数量。一般常见的数据包这里都是0,如果不是0,则后面是具体的协议头部定义:
(1)、一个 AMF0 字符串来记录头部名称
(2)、一个AMF0 数据实体记录具体的头部内容 - 消息数据列表
首先是一个 BE 编码的16位无符号整数,来标记消息的数量,然后后面跟具体的 AMF 0 格式的数据内容。常见的格式封装在这里直接以 0x11 开始,转入 AMF 3 格式的对象,也有的是以 AMF0 数组开始,然后数组里面是 AMF 3 格式的对象列表。
2、解析没有头部标记的纯消息数据流
这种格式的数据流,用户必需明确知道它是 AMF 0 还是 AMF 3 格式的,否则就会解析失败。QAMF 提供了两个函数分别对应这个解析:
- ParseAMF3Data/TryParseAMF3Data
解析 AMF 3 格式的数据内容,至于加 Try 的区别,参考上面的描述; - ParseAMF0Data/TryParseAMF0Data
解析 AMF 0 格式的数据内容。
注意一点,解析时,会在 TQAMF 对象的 Messages 里创建一个子结点,然后将解析的结点保存到相应的子结点下面。
3、编码 AMF 数据流
QAMF 目前的内测版本编码存在一些限制,如:对象只会编码为动态内联的对象(格式标记为11),而不会支持 DSK等外部类别对象的编码。将来随着对格式的进一步理解,会考虑添加支持;
而编码为 AMF 数据流的函数为 Encode。它会返回一个 TBytes 类型的字节数组,来保存编码后的结果。SaveToStream/SaveToFile 实际上调用了它保存到流或文件当中。
这里,要注意:TQAMF 的 Encode 编码会包含头部,如果要不包含头部的结果,直接调用相应消息结点的 Encode 就可以了。比如下面的代码是带有协议头部的:
var AMF:TQAMF; ABytes:TBytes; begin AMF:=TQAMF.Create; try .... ABytes:=AMF.Encode; finally FreeAndNil(AMF); end; end;
而下面的代码将只包含第一个消息的数据体,而没有任何头部内容。
var AMF:TQAMF; ABytes:TBytes; begin AMF:=TQAMF.Create; try .... ABytes:=AMF.Messages[0].Encode; finally FreeAndNil(AMF); end; end;
4、结点的增、删、查、改
好吧,这块简单说一下:
- 调用 Add 增加子结点,然后用 AsXXX 设置子结点的值,用 KeyAsXXX 设置子结点的键值。
- 调用 Delete 删除指定的子结点,调用 Clear 清除所有的子结点。
- 查找的实现暂时没有处理,将来会支持 ItemByName/ItemByPath/ItemByRegEx 接口(和 QJson一样:) )。
- 修改类型的话,直接设置结点的 DataType 属性,修改值的话,用 AsXXX ,修改键的话,用 KeyAsXXX。
因为是内测的版本,现在主要是完成解析和编码这块,至于其它的,再根据需要一步步完善,包括将来的 RTTI 支持。
好了,源码是最好的老师,有问题读源码和格式规范吧。希望大家用得愉快。