gpt4 book ai didi

c# - 使用 int NetworkStream.Read(Span) 接收完整的网络流

转载 作者:行者123 更新时间:2023-12-03 23:44:13 27 4
gpt4 key购买 nike

正如标题所说,我正在尝试将新的 (C# 8.0) 对象 (Span) 用于我的网络项目。在我之前的实现中,我了解到在尝试使用其内容之前必须确保 NetworkStream 已收到完整的缓冲区,否则,根据连接,另一端接收到的数据可能不完整。

while (true)
{
while (!stream.DataAvailable)
Thread.Sleep(10);

int received = 0;
byte[] response = new byte[consumerBufferSize];

//Loop that forces the stream to read all incoming data before using it
while (received < consumerBufferSize)
received += stream.Read(response, received, consumerBufferSize - received);

string[] message = ObjectWrapper.ConvertByteArrayToObject<string>(response);
consumerAction(this, message);
}
但是,它引入了一种不同的读取网络流数据的方法 (Read(Span))。假设 stackalloc 将有助于提高性能,我正在尝试迁移我的旧实现以适应这种方法。这是它现在的样子:
while (true)
{
while (!stream.DataAvailable)
Thread.Sleep(10);

Span<byte> response = stackalloc byte[consumerBufferSize];

stream.Read(response);

string[] message = ObjectWrapper.ConvertByteArrayToObject<string>(response).Split('|');
consumerAction(this, message);
}
但是现在我如何确定缓冲区已被完全读取,因为它没有提供像我使用的方法那样的方法?
编辑:
//Former methodd
int Read (byte[] buffer, int offset, int size);
//The one I am looking for
int Read (Span<byte> buffer, int offset, int size);

最佳答案

我不确定我明白你在问什么。使用 Span<byte> 时,您在第一个代码示例中依赖的所有相同功能仍然存在.Read(Span<byte>)重载仍然返回读取的字节数。而且由于Span<byte>不是缓冲区本身,而只是进入缓冲区的窗口,您可以更新 Span<byte>值来指示读取附加数据的新起点。拥有读取的字节数并能够指定下一次读取的偏移量是在旧示例中​​复制功能所需的全部内容。当然,您目前没有任何保存原始缓冲区引用的代码;你也需要添加它。
我希望这样的事情可以正常工作:

while (true)
{
while (!stream.DataAvailable)
Thread.Sleep(10);

byte* response = stackalloc byte[consumerBufferSize];

while (received < consumerBufferSize)
{
Span<byte> span = new Span<byte>(response, received, consumerBufferSize - received);

received += stream.Read(span);
}

// process response here...
}
请注意,这需要 unsafe码因方式 stackalloc作品。您只能通过使用 Span<T> 来避免这种情况。并每次分配新块。当然,这最终会吃光你所有的筹码。
由于在您的实现中,您显然将一个线程专用于这个无限循环,我不知道如何 stackalloc很有帮助。您不妨在堆中分配一个长期存在的缓冲区数组并使用它。
换句话说,我真的不明白这比使用原始 Read(byte[], int, int) 有什么好处使用常规托管数组重载。但上面是你如何让代码工作。

旁白:您应该了解异步 API 的工作原理。由于您已经在使用 NetworkStream , async/ await图案很自然。不管你使用什么 API,循环检查 DataAvailable只是简单的废话。不要那样做。 Read()方法已经是一个阻塞方法;您不需要等待数据出现在单独的循环中,因为 Read()直到有一些方法才会返回。

关于c# - 使用 int NetworkStream.Read(Span<Bytes>) 接收完整的网络流,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63862805/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com