【发布时间】:2022-08-20 21:26:08
【问题描述】:
描述
我想使用它们的抽象 Stream 父类从 NetworkStream 或 SSLStream 异步读取。从流中异步读取有不同的方法:
- 异步编程模型 (APM):它使用
BeginRead和EndRead操作。 - 任务并行库 (TPL):它使用
Task并创建任务延续。 - 基于任务的异步模式 (TAP):操作带有后缀异步并且可以使用
async和await关键字。
我最感兴趣的是使用轻敲模式来实现异步读操作。下面的代码,异步读取到流的末尾并以字节数组的形式返回数据:
internal async Task<byte[]> ReadToEndAsync(Stream stream)
{
byte[] buffer = new byte[4096];
using (MemoryStream memoryStream = new MemoryStream())
{
int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
while (bytesRead != 0)
{
// Received datas were aggregated to a memory stream.
await memoryStream.WriteAsync(buffer, 0, bytesRead);
bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
}
return memoryStream.ToArray();
}
}
缓冲区大小为 4096kB。如果传输的数据大于缓冲区大小,则它将继续读取直到 0(零),即流的末尾。它适用于FileStream,但它在使用NetworkStream 或SslStream 的ReadAsync 操作中无限期挂起。这两个流的行为与其他流不同。
问题在于网络流ReadAsync 只会在Socket 通信关闭时返回0(零)。不过我愿意不是每次通过网络传输数据时都希望关闭通信。
问题
如何在不关闭Socket 通信的情况下避免ReadAsync 的阻塞调用?
-
如果套接字打开但没有可用数据,您会期望表示与该套接字的连接的流的
ReadAsync无限期挂起,直到数据到达、套接字关闭或触发取消。使用... await ReadAsync(...)只阻塞等待的任务,允许其他任务继续处理。 -
没错。但我需要当前接收数据的结果。因此,我也等待 ReadToEndAsync 方法导致阻塞。
-
考虑使用 TPL 数据流创建网格,docs.microsoft.com/en-us/dotnet/standard/parallel-programming/…。但是,您不能既等到结束又在结束前开始处理。您将需要具有中间缓冲的并发任务。
-
@Jodrell 感谢您指出 DataFlow 编程模型。事实证明,它可以与 async 和 await 运算符一起使用 docs.microsoft.com/en-us/dotnet/standard/parallel-programming/…
-
TPL 数据流类型专为使用 TAP 异步/等待而设计。它们可以使您免于编写一些有风险的管道。我的观点不是关于 Dataflow 的适用性,而是需要稍微调整一下你的观点。
标签: c# sockets asynchronous .net-standard-2.0 networkstream