Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/276.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何将字节[]缓冲区合成到列表中<;字节>;?_C#_.net_Networking - Fatal编程技术网

C# 如何将字节[]缓冲区合成到列表中<;字节>;?

C# 如何将字节[]缓冲区合成到列表中<;字节>;?,c#,.net,networking,C#,.net,Networking,因此,我使用大小为1024的缓冲区(字节[])通过套接字接收数据,我想将读取的数据组合在一起,以形成整个数据包,如果它们大于1024字节。我选择了一个列表来存储整个数据包,我想做的是在数据包进入时将读取的每个缓冲区添加到其中。我想做: List.AddRange(Buffer); 但如果缓冲区未满,则会将一堆空字节填充到底。所以很自然,我想做的是只向列表中添加一定范围的字节,但是没有这样的方法。我总是可以创建一个临时字节数组,精确地表示接收到的字节数,然后使用AddRange()得到我想要的结

因此,我使用大小为1024的缓冲区(字节[])通过套接字接收数据,我想将读取的数据组合在一起,以形成整个数据包,如果它们大于1024字节。我选择了一个列表来存储整个数据包,我想做的是在数据包进入时将读取的每个缓冲区添加到其中。我想做:

List.AddRange(Buffer);
但如果缓冲区未满,则会将一堆空字节填充到底。所以很自然,我想做的是只向列表中添加一定范围的字节,但是没有这样的方法。我总是可以创建一个临时字节数组,精确地表示接收到的字节数,然后使用AddRange()得到我想要的结果,但我觉得这很愚蠢。更不用说在每次读取数据时创建然后丢弃一个数组,这对可伸缩多用户服务器的性能没有好处


有没有办法通过列表来实现这一点?或者我可以使用其他数据结构吗?

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


如果您没有详细信息,就很难做到更简洁。

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


如果没有详细信息,就很难做到更简洁。

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

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

您可以实现自己的IEnumerable实现,该实现只从数组中检索所需的字节。然后你可以做:

AddRange(新的BufferEnumerator(Buffer))

编辑 您还可以查看:

新系统。阵列整理(缓冲区,0,已接收的字节数)


我不确定ArraySegment是否有效我记得读过它的一些缺点,但不记得具体细节。

您可以实现自己的IEnumerable实现,它只从数组中检索所需的字节。然后你可以做:

AddRange(新的BufferEnumerator(Buffer))

编辑 您还可以查看:

新系统。阵列整理(缓冲区,0,已接收的字节数)

我不确定ArraySegment是否有效我记得读过它的一些缺点,但不记得具体细节。

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

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

您可以使用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;
}
编辑:将Array.Copy()替换为Buffer.BlockCopy(),就像Quintin Robinson在评论中建议的那样。

您可以使用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;
}
编辑:将Array.Copy()替换为Buffer.BlockCopy(),就像Quintin Robinson在评论中建议的那样。

您真的需要结果成为
列表吗?以后你打算用它做什么?如果您真的只需要一个
IEnumerable
,我建议您创建如下内容:

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();
    }
}
使用系统;
使用系统集合;
使用System.Collections.Generic;
公共类ArraySegmentConcatenator:IEnumerable
{
专用只读列表段=
新列表();
公共IEnumerator GetEnumerator()
{
foreach(按段排列分段段)
{
对于(int i=0;i
然后,每次只需添加相关的片段即可。当然,最终可能会浪费大量内存,而且每次都必须小心创建一个新的缓冲区(而不是再次读取原始缓冲区),但这在其他方面会很有效。

您真的需要结果成为一个
列表吗?以后你打算用它做什么?如果您真的只需要一个
IEnumerable
,我建议您创建如下内容:

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();
    }
}
使用系统;
使用系统集合;
使用System.Collections.Generic;
公共类ArraySegmentConcatenator:IEnumerable
{
专用只读列表段=
新列表();
公共IEnumerator GetEnumerator()
{
foreach(按段排列分段段)
{
对于(int i=0;i
然后,每次只需添加相关的片段即可。当然,最终可能会浪费大量内存,而且每次都必须小心地创建一个新的缓冲区(而不是再次读取原始缓冲区),但这样会更有效