Files
TouchSocket/handbook/docs/customunfixedheaderdatahandlingadapter.mdx
2023-10-26 09:34:02 +08:00

141 lines
4.9 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
id: customunfixedheaderdatahandlingadapter
title: 模板解析“非固定包头”数据适配器
---
### 定义
命名空间TouchSocket.Core <br/>
程序集:[TouchSocket.Core.dll](https://www.nuget.org/packages/TouchSocket.Core)
## 一、说明
有时候我们需要解析的数据的包头是不定的例如HTTP数据格式其数据头和数据体由“\r\n”隔开而数据头又因为请求者的请求信息的不同头部数据量不固定而数据体的长度也是由数据头的ContentLength的值显式指定的所以可以考虑使用**CustomUnfixedHeaderDataHandlingAdapter**解析。
## 二、特点
1. 可以自由适配**所有**的数据协议。
2. 可以随意定制数据协议。
3. 可以与**任意语言、框架**对接数据。
## 三、使用
客户端与服务器均适用。下列以服务器为例。
步骤
1. 声明新建类实现IFixedHeaderRequestInfo接口此对象即为存储数据的实体类可在此类中声明一些属性以备使用。
2. 声明新建类继承CustomUnfixedHeaderDataHandlingAdapter并且以步骤1声明的类作为泛型。并实现对应抽象方法。
3. TouchSocketConfig配置中设置。
4. 通过Received事件、方法、插件中的RequestInfo对象强转为步骤1声明的类型然后读取其属性值以备使用。
【MyUnfixedHeaderRequestInfo】
首先新建MyFixedHeaderRequestInfo类然后实现**IUnfixedHeaderRequestInfo**用户自定义固定包头接口。
然后在**OnParsingHeader**函数执行结束时,对实现的`BodyLength`属性作出赋值以此来决定后续还应该接收多少数据作为Body 。
```csharp
public class MyUnfixedHeaderRequestInfo : IUnfixedHeaderRequestInfo
{
private int bodyLength;
/// <summary>
/// 接口实现,标识数据长度
/// </summary>
public int BodyLength
{
get { return bodyLength; }
}
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(ByteBlock byteBlock)
{
//此处逻辑和固定包头模板基本一致。也需要对BodyLength作出赋值。
//但是不同固定包头的是,需要自己移动已读的游标。并且返回正确的值。
//下列通过假逻辑实现Http协议的解析。
//从现有的可读数据中,读取“\r\n\r\n”以此来分割http的headers和body。
int index = byteBlock.Buffer.IndexOfFirst(byteBlock.Pos, byteBlock.CanReadLen, Encoding.UTF8.GetBytes("\r\n\r\n"));
if (index > 0)
{
//索引到了“\r\n\r\n”以此推断出在当前缓存区中由byteBlock.Pos至index的数据即为headers。
int headerLength = index - byteBlock.Pos;
string headers = Encoding.UTF8.GetString(byteBlock.Buffer, byteBlock.Pos,headerLength);//解码headers
byteBlock.Pos += headerLength;//然后将缓存区的游标移至headers结束的位置。
//最后通过headers解析出后续的body的长度然后在此处赋值。
this.bodyLength = 0;//此处的0是占位值。
return true;
}
else
{
//没索引到“\r\n\r\n”以此推断出在当前缓存区中header的接收尚未完成
//所以返回false并且不需要修改游标。
return false;
}
}
}
```
新建MyCustomUnfixedHeaderDataHandlingAdapter继承**CustomUnfixedHeaderDataHandlingAdapter**。
```csharp
public class MyCustomUnfixedHeaderDataHandlingAdapter : CustomUnfixedHeaderDataHandlingAdapter<MyUnfixedHeaderRequestInfo>
{
protected override MyUnfixedHeaderRequestInfo GetInstance()
{
return new MyUnfixedHeaderRequestInfo();
}
}
```
【接收】
```csharp
TcpService service = new TcpService();
service.Received = (client, e) =>
{
//接收信息在CustomDataHandlingAdapter派生的适配器中byteBlock将为nullrequestInfo将为适配器定义的泛型
if (e.RequestInfo is MyUnfixedHeaderRequestInfo myRequestInfo)
{
//此处可以处理MyUnfixedHeaderRequestInfo的相关信息了。
string body = Encoding.UTF8.GetString(myRequestInfo.Body, 0, myRequestInfo.Body.Length);
}
};
service.Setup(new TouchSocketConfig()//载入配置
.SetListenIPHosts(new IPHost[] { new IPHost(7790) })
.SetDataHandlingAdapter(() => { return new MyCustomUnfixedHeaderDataHandlingAdapter(); }))//配置适配器
.Start();//启动
```
:::tip 提示
上述创建的适配器客户端与服务器均适用。
:::