说明
和用户自定义适配器相比,使用模板解析将会更加简单流程。例如在上节所说的数据格式,前三个字节是固定长度的,为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());
}