ET---TBuffer学习笔记

TBuffer

请大家关注我的微博:@NormanLin_BadPixel坏像素


3.0已经把TBuffer整合到CircularBuffer。不过建议大家继续看下去吧,毕竟作者的思路大致是没变化的,这篇我可能讲的比较详细。(毕竟我花心思写了T_T)


大致浏览了一下,难道这里用到了类似这篇文章提到的技术?(需要安全上网工具)我只是随便一猜,大家还是继续看代码吧。

public const int ChunkSize = 8192;

这里是定义了一个常量,决定了每个缓存区块的大小为8KB。为什么是8KB呢?可能是8KB的数据传输比较快吧。

private readonly LinkedList<byte[]> bufferList = new LinkedList<byte[]>();

哇,看到这里我才发现自己的知识量是多么的浅薄。我竟然连LinkedList都不知道。羞于见人。赶紧去学习一下

这真的是一个很方便的类型。这里我忍不住想要为大家介绍一下。我们平常都在使用List<>。当我们在遍历List的时候,我们遍历的是里面的每一个值。而当我们在遍历LinkedList<>的时候,我们遍历的是它的节点LinkedListNode<>。这个节点可就神奇了,它就像里面的节点,储存了与它相连的数据,不过它储存的不是左子树右子树,而是它的前节点后节点。储存了这些信息有什么用呢?这样方便我们插入啊!普通的链表List,当我们插入一个新数据的时候,我们需要把插入的地方后面的数据全部都往后移,而这个LinkedList只要修改插入节点的前节点的后节点,插入节点的前节点就好了。(有点绕哈哈,不过很好理解,无非是一个顺序问题。)而且,这个可以很方便的删除第一个节点或者最后一个节点,用来做有限撤销操作的储存非常合适。

看到这,我发现我其实对这个类型并不是很陌生,在大学里数据结构课程上老师就有对这种结构进行过描述。只不过我不知道C#里面就是LinkedList。(其实就是没记起来:_))

复习了LinkedList<>(厚颜无耻),我们继续往下看。

public int LastIndex { get; set; }
public int FirstIndex { get; set; }

这俩个变量我们现在还不知道他们是做啥的,大概是对这个缓冲区有效信息的范围下标的储存吧。因为我们的数据不一定刚好就填充满8KB的区块,可能只填充了一半,这个时候,就需要标识有效数据的下标了。

public TBuffer()
{
    this.bufferList.AddLast(new byte[ChunkSize]);
}

OK,我们在构造函数里就先给了双向链表一个值,虽然是空的数组,但保证bufferList不为空嘛。

public int Count{get;}

这个Count属性的获取器代码很容易看懂。
后面的AddLastRemoveFirstbyte[] Firstbyte[] Last也一样,不需要我讲的吧。我们来看看重要的收发数据。我们先来看看发送数据,这里的发送数据不是说向远端发送数据,而是往这个缓冲区发送数据。

public void SendTo(byte[] buffer)
{
    int alreadyCopyCount = 0;
    while (alreadyCopyCount < buffer.Length)
    {
        if (this.LastIndex == ChunkSize)
        {
            this.bufferList.AddLast(new byte[ChunkSize]);
            this.LastIndex = 0;
        }

        int n = buffer.Length - alreadyCopyCount;
        if (ChunkSize - this.LastIndex > n)
        {
            Array.Copy(buffer, alreadyCopyCount, this.bufferList.Last.Value, this.LastIndex, n);
            this.LastIndex += buffer.Length - alreadyCopyCount;
            alreadyCopyCount += n;
        }
        else
        {
            Array.Copy(buffer, alreadyCopyCount, this.bufferList.Last.Value, this.LastIndex, ChunkSize - this.LastIndex);
            alreadyCopyCount += ChunkSize - this.LastIndex;
            this.LastIndex = ChunkSize;
        }
    }
}

首先,alreadyCopyCount这个变量记录的是已经往缓冲区里面存入的数据量。while循环我就不多说了。
if (this.LastIndex == ChunkSize),这种情况是到了缓冲区里面的小区块满了的时候,需要对缓冲区进行扩增,并把LastIndex归0,因为是开始往新的区块里存了。

n代表剩余的数据量,如果剩余的数据量小于区块剩余的量,则把buffer的[alreadyCopyCount,alreadyCopyCount + n)区间内的数据拷贝到最新的区块也就是bufferList的最后一个节点的值LastIndex下标之后。这是Array.Copy的方法,大家了解一下就理解了。此后,对LastIndexalreadyCopyCount的值进行更新。

如果剩余的数据量还是很大,超过了每个区块的最大8KB,那就要对数据进行分区块处理,也就是else里面的代码做的处理。

好的,我们继续来看接收数据,当然,这里的接收数据是从缓冲区中接收也就是读取数据。

public void RecvFrom(byte[] buffer)
{
    if (this.Count < buffer.Length || buffer.Length == 0)
    {
        throw new Exception($"bufferList size < n, bufferList: {this.Count} buffer length: {buffer.Length}");
    }
    int alreadyCopyCount = 0;
    while (alreadyCopyCount < buffer.Length)
    {
        int n = buffer.Length - alreadyCopyCount;
        if (ChunkSize - this.FirstIndex > n)
        {
            Array.Copy(this.bufferList.First.Value, this.FirstIndex, buffer, alreadyCopyCount, n);
            this.FirstIndex += n;
            alreadyCopyCount += n;
        }
        else
        {
            Array.Copy(this.bufferList.First.Value, this.FirstIndex, buffer, alreadyCopyCount, ChunkSize - this.FirstIndex);
            alreadyCopyCount += ChunkSize - this.FirstIndex;
            this.FirstIndex = 0;
            this.bufferList.RemoveFirst();
        }
    }
}

经过了前面的解释,这里无非就是对上面存的操作进行一次逆操作。不过需要注意的是,用来存读取得到的数据的byte[] 长度不能为0也不能超过缓冲区中原有的数据长度。这样可能是为了避免出现空的字节导致后续反序列化出现问题吧。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值