在C#中缓冲字节数据 [英] Buffering byte data in 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 = ...部分(或进行过载可选参数,并检查或其他)。 P>
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 < _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 < _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 < 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屋!