C# 如何将字节[]缓冲区合成到列表中<;字节>;?
因此,我使用大小为1024的缓冲区(字节[])通过套接字接收数据,我想将读取的数据组合在一起,以形成整个数据包,如果它们大于1024字节。我选择了一个列表来存储整个数据包,我想做的是在数据包进入时将读取的每个缓冲区添加到其中。我想做:C# 如何将字节[]缓冲区合成到列表中<;字节>;?,c#,.net,networking,C#,.net,Networking,因此,我使用大小为1024的缓冲区(字节[])通过套接字接收数据,我想将读取的数据组合在一起,以形成整个数据包,如果它们大于1024字节。我选择了一个列表来存储整个数据包,我想做的是在数据包进入时将读取的每个缓冲区添加到其中。我想做: List.AddRange(Buffer); 但如果缓冲区未满,则会将一堆空字节填充到底。所以很自然,我想做的是只向列表中添加一定范围的字节,但是没有这样的方法。我总是可以创建一个临时字节数组,精确地表示接收到的字节数,然后使用AddRange()得到我想要的结
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
然后,每次只需添加相关的片段即可。当然,最终可能会浪费大量内存,而且每次都必须小心地创建一个新的缓冲区(而不是再次读取原始缓冲区),但这样会更有效