如何将byte []缓冲区复合为List <byte>?</byte>

时间:2009-03-04 20:26:17

标签: c# .net networking

所以我使用大小为1024的缓冲区(byte [])通过套接字接收数据,并且我希望在它们大于1024字节的情况下将读取组合在一起形成整个数据包。我选择了一个List来存储整个数据包,我想要做的是添加每个缓冲区读取它。我想做:

List.AddRange(Buffer);

但是如果缓冲区未满,则会将一堆空字节填充到最后。所以我自然想要做的只是在List中添加一定范围的字节,但是没有这样的方法。我总是可以创建一个完全接收的字节数的临时字节数组,然后使用AddRange()并得到我想要的结果,但这对我来说似乎很愚蠢。更不用说它会创建然后在每次读取数据时丢弃一个数组,这对可伸缩多用户服务器上的性能不利。

有没有办法用List做到这一点?或者我可以使用其他一些数据结构吗?

6 个答案:

答案 0 :(得分:6)

如果您使用的是C#3.5(LINQ)

list.AddRange(buffer.Take(count));

答案 1 :(得分:2)

实际上需要结果是List<byte>吗?之后你打算用它做什么?如果你真的只需要一个IEnumerable<byte>我建议创建这样的东西:

using System;
using System.Collections;
using System.Collections.Generic;

public class ArraySegmentConcatenator<T> : IEnumerable<T>
{
    private readonly List<ArraySegment<T>> segments =
        new List<ArraySegment<T>>();

    public IEnumerator<T> GetEnumerator()
    {
        foreach (ArraySegment<T> segment in segments)
        {
            for (int i=0; i < segment.Count; i++)
            {
                yield return segment.Array[i+segment.Offset];
            }
        }
    }

    public void Add(ArraySegment<T> segment)
    {
        segments.Add(segment);
    }

    public void Add(T[] array)
    {
        segments.Add(new ArraySegment<T>(array));
    }

    public void Add(T[] array, int count)
    {
        segments.Add(new ArraySegment<T>(array, 0, count));
    }

    public void Add(T[] array, int offset, int count)
    {
        segments.Add(new ArraySegment<T>(array, offset, count));
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

然后您可以每次添加相关的细分。当然,你最终可能会浪费大量的内存,而且每次都要小心创建一个新的缓冲区(而不是再次阅读原文),但在其他方面它会很有效。

答案 2 :(得分:1)

对于.Net3.5,您可以使用.Take()扩展方法仅返回您收到的实际字节数。

答案 3 :(得分:0)

我不知道您正在使用什么协议,或者您是否正在实现自定义协议,但如果您确定了大小,则可以使用Buffer.BlockCopy直接将字节复制到新数组以添加到您的列表。

当你没有具体细节时,很难更简洁。

答案 4 :(得分:0)

您可以实现自己的IEnumerable实现,该实现仅从数组中检索您想要的字节。然后你可以这样做:

List.AddRange(new BufferEnumerator(Buffer));

修改

您还可以查看:

new System.ArraySegment(Buffer,0,numBytesRecieved)

如果ArraySegment可行,我不肯定我记得读过它的一些缺点但不记得细节。

答案 5 :(得分:0)

您可以使用Array.Copy()并仅使用数组来构建目标缓冲区:

byte[] recvBuffer = new byte[1024];
byte[] message = new byte[0];
int nReaded;

while ((nReaded = ....Read(recvBuffer, 1024) > 0)
{
  byte[] tmp = new byte[message.Length + nReaded];
  Buffer.BlockCopy(message, 0, tmp, 0, message.Length);
  Buffer.BlockCopy(recvBuffer, 0, tmp, message.Length, nReaded);
  message = tmp;
}

编辑:使用与Quintin Robinson在评论中建议的Buffer.BlockCopy()替换Array.Copy()。