--- 
id: custombigunfixedheaderdatahandlingadapter
title: 模板解析“大数据不固定包头”数据适配器
---

### 定义

命名空间：TouchSocket.Core <br/>
程序集：[TouchSocket.Core.dll](https://www.nuget.org/packages/TouchSocket.Core)

## 一、说明

大数据不固定包头，是对不固定的包头模板的补充，一般来是，不固定包头适配器，不能工作于超过2G的数据，但是在少数情况下，会有大量的数据传输需求。所以这部分的业务，可以用大数据不固定包头实现。


## 二、特点

1. 可以随意定制数据协议。
2. 可以与**任意语言、框架**对接数据。
3. 可以接收**理论无限大**的数据。


## 三、创建适配器

客户端与服务器均适用。下列以服务器为例。

步骤

1. 声明新建类，实现`IBigUnfixedHeaderRequestInfo`接口，此对象即为存储数据的实体类，可在此类中声明一些属性，以备使用。
2. 声明新建类，继承`CustomBigUnfixedHeaderDataHandlingAdapter`，并且以步骤1声明的类作为泛型。并实现对应抽象方法。
3. `TouchSocketConfig`配置中设置。
4. 通过`Received`（事件、方法、插件）中的`RequestInfo`对象，强转为步骤1声明的类型，然后读取其属性值，以备使用。

【MyBigUnfixedHeaderRequestInfo】

首先，新建`MyBigUnfixedHeaderRequestInfo`类，然后实现`IBigUnfixedHeaderRequestInfo`用户自定义不固定包头接口。

然后在`OnParsingHeader`函数执行结束时，对实现的`BodyLength`和`HeaderLength`属性作出赋值，以此来决定，后续还应该接收多少数据作为`Body` 。

同时最重要的是把ByteBlock.Position属性，设置为适当位置，表示已经消费了多少数据。

```csharp showLineNumbers
class MyBigUnfixedHeaderRequestInfo : IBigUnfixedHeaderRequestInfo
{
    /// <summary>
    /// 自定义属性，标识数据类型
    /// </summary>
    public byte DataType { get; set; }

    /// <summary>
    /// 自定义属性，标识指令类型
    /// </summary>
    public byte OrderType { get; set; }

    /// <summary>
    /// 自定义属性，标识实际数据
    /// </summary>
    public byte[] Body { get; set; }


    List<byte> m_bytes = new List<byte>();

    private int m_headerLength;
    private long m_bodyLength;

    #region 接口成员
    int IBigUnfixedHeaderRequestInfo.HeaderLength => m_headerLength;

    long IBigUnfixedHeaderRequestInfo.BodyLength => m_bodyLength;

    void IBigUnfixedHeaderRequestInfo.OnAppendBody(ReadOnlySpan<byte> buffer)
    {
        //每次追加数据
        m_bytes.AddRange(buffer.ToArray());
    }

    bool IBigUnfixedHeaderRequestInfo.OnFinished()
    {
        if (m_bytes.Count == this.m_bodyLength)
        {
            this.Body = m_bytes.ToArray();
            return true;
        }
        return false;
    }

    bool IBigUnfixedHeaderRequestInfo.OnParsingHeader<TByteBlock>(ref TByteBlock byteBlock)
    {
        if (byteBlock.CanReadLength<3)//判断可读数据是否满足一定长度
        {
            return false;
        }

        var pos= byteBlock.Position;//可以先记录游标位置，当解析不能进行时回退游标

        //在该示例中，第一个字节表示后续的所有数据长度，但是header设置的是3，所以后续还应当接收length-2个长度。
        this.m_bodyLength = byteBlock.ReadByte() - 2;
        this.DataType = byteBlock.ReadByte();
        this.OrderType = byteBlock.ReadByte();


        //当执行到这里时，byteBlock.Position已经递增了3个长度。
        //所以无需再其他操作，如果是其他，则需要手动移动byteBlock.Position到指定位置。

        this.m_headerLength = 3;//表示Header消耗了3个字节，实际上可以省略这一行，但是为了性能，最好加上

        return true;
    }
    #endregion
}
```

新建`MyCustomBigUnfixedHeaderDataHandlingAdapter`继承`CustomBigUnfixedHeaderDataHandlingAdapter`。

```csharp showLineNumbers
class MyCustomBigUnfixedHeaderDataHandlingAdapter : CustomBigUnfixedHeaderDataHandlingAdapter<MyBigUnfixedHeaderRequestInfo>
{
    protected override MyBigUnfixedHeaderRequestInfo GetInstance()
    {
        return new MyBigUnfixedHeaderRequestInfo();
    }
}
```

## 四、使用

```csharp {7,34} showLineNumbers
private static async Task<TcpClient> CreateClient()
{
    var client = new TcpClient();
    //载入配置
    await client.SetupAsync(new TouchSocketConfig()
         .SetRemoteIPHost("127.0.0.1:7789")
         .SetTcpDataHandlingAdapter(() => new MyCustomBigUnfixedHeaderDataHandlingAdapter())
         .ConfigureContainer(a =>
         {
             a.AddConsoleLogger();//添加一个日志注入
         }));

    await client.ConnectAsync();//调用连接，当连接不成功时，会抛出异常。
    client.Logger.Info("客户端成功连接");
    return client;
}

private static async Task<TcpService> CreateService()
{
    var service = new TcpService();
    service.Received = (client, e) =>
    {
        //从客户端收到信息

        if (e.RequestInfo is MyBigUnfixedHeaderRequestInfo myRequest)
        {
            client.Logger.Info($"已从{client.Id}接收到：DataType={myRequest.DataType},OrderType={myRequest.OrderType},消息={Encoding.UTF8.GetString(myRequest.Body)}");
        }
        return Task.CompletedTask;
    };

    await service.SetupAsync(new TouchSocketConfig()//载入配置
         .SetListenIPHosts("tcp://127.0.0.1:7789", 7790)//同时监听两个地址
         .SetTcpDataHandlingAdapter(() => new MyCustomBigUnfixedHeaderDataHandlingAdapter())
         .ConfigureContainer(a =>
         {
             a.AddConsoleLogger();//添加一个控制台日志注入（注意：在maui中控制台日志不可用）
         })
         .ConfigurePlugins(a =>
         {
             //a.Add();//此处可以添加插件
         }));
    await service.StartAsync();//启动
    service.Logger.Info("服务器已启动");
    return service;
}
```

:::tip 提示

上述创建的适配器客户端与服务器均适用。

:::  