在C#中缓冲字节数据 [英] Buffering byte data in C#

查看:154
本文介绍了在C#中缓冲字节数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的应用程序读取TCP套接字字节,需要缓冲起来,这样我可以从他们身上以后提取信息。由于TCP的性质我可能会部分或多个消息一读,所以每次看后,我想检查缓冲区以及可提取尽可能多的充分的信息。

因此​​,我希望有一个类,允许我做了以下内容:

  • 在任意追加byte []的数据,将其
  • 检查内容而不消耗它,特别是检查的内容的数量,并还搜索某一字节或字节
  • 的存在
  • 提取和消费数据作为一个byte []的一部分,而在那里留下休息了未来的阅读

我希望我想要的可以用1或.NET库多个现有类来完成,但我不知道哪些。 System.IO.MemoryStream 看起来接近我想要的,但(一)目前尚不清楚是否它适合被用来作为缓冲(不读取数据的能力得到删除吗?),并(二)读取和写入操作似乎发生在同一个地方 - 的流的当前位置进行下一个读或写操作可能发生的位置。的 - 这不是我想。我需要被写入到结束,从前面看。

解决方案

只需使用一个大的字节数组,Array.Copy - 它应该做的伎俩。 如果没有,使用List<字节>

如果您使用数组,你必须执行的指标,它(在那里你复制其他数据)自己(同样用于检查内容的大小),但它的简单。

如果你有兴趣:这是一个简单的实现了循环缓冲区的。该测试应该运行(我扔了几个单元测试它,但它并没有检查所有关键路径):

 公共类ReadWriteBuffer
{
    私人只读的byte [] _​​buffer;
    私人诠释_startIndex,_endIndex;

    公共ReadWriteBuffer(INT容量)
    {
        _buffer =新的字节[容量]
    }

    公众诠释计数
    {
        得到
        {
            如果(_endIndex> _startIndex)
                返回_endIndex  -  _startIndex;
            如果(_endIndex&放大器; LT _startIndex)
                返回(_buffer.Length  -  _startIndex)+ _endIndex;
            返回0;
        }
    }

    公共无效写入(byte []的数据)
    {
        如果(计数+ data.Length> _buffer.Length)
            抛出新的异常(缓冲区溢出);
        如果(_endIndex + data.Length> = _buffer.Length)
        {
            VAR endLen = _buffer.Length  -  _endIndex;
            VAR remainingLen = data.Length  -  endLen;

            Array.Copy(数据,0,_buffer,_endIndex,endLen);
            Array.Copy(数据,endLen,_buffer,0,remainingLen);
            _endIndex = remainingLen;
        }
        其他
        {
            Array.Copy(数据,0,_buffer,_endIndex,data.Length);
            _endIndex + = data.Length;
        }
    }

    公共byte []的读取(INT LEN,布尔keepData = FALSE)
    {
        如果(LEN>计数)
            抛出新的异常(缓冲区数据不足);
        VAR的结果=新的字节[长度];
        如果(_startIndex + LEN和放大器; LT _buffer.Length)
        {
            Array.Copy(_buffer,_startIndex,结果,0,len个);
            如果(!keepData)
                _startIndex + = LEN;
            返回结果;
        }
        其他
        {
            VAR endLen = _buffer.Length  -  _startIndex;
            VAR remainingLen = LEN  -  endLen;
            Array.Copy(_buffer,_startIndex,结果,0,endLen);
            Array.Copy(_buffer,0,因此,endLen,remainingLen);
            如果(!keepData)
                _startIndex = remainingLen;
            返回结果;
        }
    }

    公共字节这个[INT指数]
    {
        得到
        {
            如果(索引> = COUNT)
                抛出新ArgumentOutOfRangeException();
            返回_buffer [(_的startIndex +指数)%_buffer.Length]。
        }
    }

    公开的IEnumerable<字节>字节
    {
        得到
        {
            对于(VAR I = _startIndex; I和LT计数;我++)
                收益回报_buffer [(_的startIndex + I)%_buffer.Length]。
        }
    }
}
 

请注意:在读code消耗 - 如果你不希望只是删除了_startIndex = ...部分(或进行过载可选参数,并检查或其他)

My app reads bytes from a TCP socket and needs to buffer them up, so that I can extract messages from them later. Due to the nature of TCP I may get partial or multiple messages in one read, so after each read I would like to inspect the buffer and extract as many full messages as are available.

Therefore I want a class that allows me to do the following:

  • append arbitrary byte[] data to it
  • inspect the content without consuming it, in particular checking the amount of content and also searching for the existence of a certain byte or bytes
  • extract and consume part of the data as a byte[], while leaving the rest in there for a future read

I expect that what I want can be done with 1 or more existing classes in the .NET library, but I'm not sure which ones. System.IO.MemoryStream looks close to what I want, but (a) it isn't clear whether it's suited to being used as a buffer (does the read data get removed from the capacity?) and (b) reads and writes seem to happen at the same place - "The current position of a stream is the position at which the next read or write operation could take place." - which is not what I want. I need to be writing to the end and reading from the front.

解决方案

Just use a big byte-array and Array.Copy - it should do the trick. If not, use List<byte>.

If you use the array you have to implement an index to it (where you copy additional data) yourself (same for checking the content-size), but it's straightforward.

If you are interested: here is a simple implementation of a "cyclic buffer". The test should run (I threw a couple unit test at it, but it didn't check all critical path):

public class ReadWriteBuffer
{
    private readonly byte[] _buffer;
    private int _startIndex, _endIndex;

    public ReadWriteBuffer(int capacity)
    {
        _buffer = new byte[capacity];
    }

    public int Count
    {
        get
        {
            if (_endIndex > _startIndex)
                return _endIndex - _startIndex;
            if (_endIndex &lt _startIndex)
                return (_buffer.Length - _startIndex) + _endIndex;
            return 0;
        }
    }

    public void Write(byte[] data)
    {
        if (Count + data.Length > _buffer.Length)
            throw new Exception("buffer overflow");
        if (_endIndex + data.Length >= _buffer.Length)
        {
            var endLen = _buffer.Length - _endIndex;
            var remainingLen = data.Length - endLen;

            Array.Copy(data, 0, _buffer, _endIndex, endLen);
            Array.Copy(data, endLen, _buffer, 0, remainingLen);
            _endIndex = remainingLen;
        }
        else
        {
            Array.Copy(data, 0, _buffer, _endIndex, data.Length);
            _endIndex += data.Length;
        }
    }

    public byte[] Read(int len, bool keepData = false)
    {
        if (len > Count)
            throw new Exception("not enough data in buffer");
        var result = new byte[len];
        if (_startIndex + len &lt _buffer.Length)
        {
            Array.Copy(_buffer, _startIndex, result, 0, len);
            if (!keepData)
                _startIndex += len;
            return result;
        }
        else
        {
            var endLen = _buffer.Length - _startIndex;
            var remainingLen = len - endLen;
            Array.Copy(_buffer, _startIndex, result, 0, endLen);
            Array.Copy(_buffer, 0, result, endLen, remainingLen);
            if (!keepData)
                _startIndex = remainingLen;
            return result;
        }
    }

    public byte this[int index]
    {
        get
        {
            if (index >= Count)
                throw new ArgumentOutOfRangeException();
            return _buffer[(_startIndex + index) % _buffer.Length];
        }
    }

    public IEnumerable<byte> Bytes
    {
        get
        {
            for (var i = _startIndex; i &lt Count; i++)
                yield return _buffer[(_startIndex + i) % _buffer.Length];
        }
    }
}

Please note: the code "consumes" on read - if you don't want that just remove the "_startIndex = ..." parts (or make a overload optional parameter and check or whatever).

这篇关于在C#中缓冲字节数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆