mirror of
https://github.com/RRQM/TouchSocket.git
synced 2025-12-19 01:46:44 +08:00
141 lines
4.9 KiB
Plaintext
141 lines
4.9 KiB
Plaintext
---
|
||
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将为null,requestInfo将为适配器定义的泛型
|
||
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 提示
|
||
|
||
上述创建的适配器客户端与服务器均适用。
|
||
|
||
::: |