说明
和用户自定义适配器相比,使用模板解析将会更加简单流程。例如在上节所说的数据格式,前三个字节是固定长度的,为3,而后续长度则由第一个字节计算可得,所以我们把类似这样的数据格式,叫做“固定包头”数据,那么,他就可以使用固定包头数据解析模板。
实现
首先,实现IFixedHeaderRequestInfo用户自定义固定包头接口,设置BodyLength属性 。
public class MyFixedHeaderRequestInfo : IFixedHeaderRequestInfo{private int bodyLength;/// <summary>/// 接口实现,标识数据长度/// </summary>public int BodyLength{get { return bodyLength; }}private byte dataType;/// <summary>/// 自定义属性,标识数据类型/// </summary>public byte DataType{get { return dataType; }}private byte orderType;/// <summary>/// 自定义属性,标识指令类型/// </summary>public byte OrderType{get { return orderType; }}private byte[] body;/// <summary>/// 自定义属性,标识实际数据/// </summary>public byte[] Body{get { return body; }}public bool OnParsingBody(byte[] body){if (body.Length == this.bodyLength){this.body = body;return true;}return false;}public bool OnParsingHeader(byte[] header){//在该示例中,第一个字节表示后续的所有数据长度,但是header设置的是3,所以后续还应当接收length-2个长度。this.bodyLength = header[0]-2;this.dataType = header[1];this.orderType = header[2];return true;}}
然后继承CustomFixedHeaderDataHandlingAdapter用户自定义固定包头适配器,实现获取实例的方法,即可。
public class MyFixedHeaderCustomDataHandlingAdapter : CustomFixedHeaderDataHandlingAdapter<MyFixedHeaderRequestInfo>{public MyFixedHeaderCustomDataHandlingAdapter(){this.MaxPackageSize = 1024;}/// <summary>/// 接口实现,指示固定包头长度/// </summary>public override int HeaderLength => 3;/// <summary>/// 获取新实例/// </summary>/// <returns></returns>protected override MyFixedHeaderRequestInfo GetInstance(){return new MyFixedHeaderRequestInfo();}}
完工。此时您已获得一个自定义的数据处理适配器。
注意:使用**_CustomDataHandlingAdapter_**及其派生类解析时,接收方收到的数据中,**_ByteBlock_**将为null,同时**_IRequestInfo_**将实现为您自定义的泛型**_TRequestInfo_**。
使用自定义适配器
自定义适配器的使用和预设的适配器一样。不过在该案例中,发送数据时,应当传入三个有效值,分别为数据类型,指令类型,其他数据。
对自定义适配器进行单元测试
适配器写完以后,需要经过缜密测试,方才能使用。在RRQM中内置了DataAdapterTester进行模拟、接收的适配器测试类,该测试类能模拟粘包、分包等情况。如果通过,则基本说明能适应99%的情况。具体使用如下:
包长度的工作机制相当于发送固定长度的数据,例如发送方多次发送数据{1,2,3,4,5}。如果设置包长度为10,则在接收时会收到{1,2,3,4,5,1,2,3,4,5},如果包长度设置为7,则会收到{1,2,3,4,5,1,2}{3,4,5,1,2,3,4},以此类推。所以在测试时应当多次设置该值,且最好不要整除发送的数据长度,以模拟更恶劣的环境
【模板适配器测试】
[Theory][InlineData(10000, 3)][InlineData(10000, 5)][InlineData(10000, 200)][InlineData(10000, 500)][InlineData(10000, 1000)]public void MyCustomDataHandlingAdapterShouldBeOk(int inputCount, int bufferLength){DataAdapterTester tester = DataAdapterTester.CreateTester(new MyCustomDataHandlingAdapter(), bufferLength);//用BufferLength模拟粘包,分包ByteBlock block = new ByteBlock();block.Write((byte)102);//写入数据长度block.Write((byte)1);//写入数据类型block.Write((byte)1);//写入数据指令byte[] buffer = new byte[100];new Random().NextBytes(buffer);block.Write(buffer);//写入数据byte[] data = block.ToArray();//输出测试时间,用于衡量适配性能output.WriteLine(tester.Run(data, inputCount, inputCount, 1000 * 2).ToString());}
