.net - 如何检测 PipeReader 何时到达数据源的末端(管道末端)?
问题描述
我们可以调用 ReadAsync() 并检查缓冲区中的读取字节...
PipeReader reader = ...;
ReadResult readResult = await reader.ReadAsync();
ReadOnlySequence<byte> buffer = readResult.Buffer;
long availableBytes = buffer.Length
如果在调用 ReadAsync 之前长度没有增加,这是否表明管道结束(没有更多字节要读取)?如果不是,那么检测“管道末端”的正确方法是什么?
我们可以像这样表示缓冲区中字节的消耗:
reader.AdvanceTo(count);
然后检查是否有任何未消耗的字节,或者未来提供字节的可能性(即生产者尚未发出信号,它已停止向管道添加新字节)
readResult.IsCompleted
但是,如果我在缓冲区中寻找一个(或多个)序列,并在使用它之前等待一个完整的序列,那么即使缓冲区包含所有可用字节并且生产者已发出完成信号,IsComplete 似乎仍然为假。
谢谢。
解决方案
.IsCompleted
确实表示管道的末端,在套接字等被关闭的意义上(而不是打开但现在没有更多数据);我希望这里发生的是你:
- 获取读取缓冲区
- 读取整个缓冲区寻找一个序列,但没有找到它
- 因此处理零字节
- 因此说
.AdvanceTo(zero)
还有一个重要的第二个重载AdvanceTo
——你不应该只告诉它你吃了什么;你应该告诉它你检查了什么,在这种情况下可能是:一切;这样做可以避免你陷入一个热循环,一遍又一遍地解析同一个不完整的帧。例如,我的一个读取循环看起来像(简化):
while (true)
{
var readResult = await input.ReadAsync();
var buffer = readResult.Buffer;
int handled = TryConsume(ref buffer); // note: this **changes** buffer, slicing (Slice)
// data from the start; when TryConsume exits, it will contain everything
// that is *left*, but we will have effectively examined all of it; we will
// have consumed any complete frames that we can from it
// advance the pipe
input.AdvanceTo(buffer.Start, buffer.End);
// exit if we aren't making progress, and nothing else will be forthcoming
if (handled == 0 && readResult.IsCompleted)
{
break; // no more data, or trailing incomplete messages
}
}
推荐阅读
- xcode - xcodebuild:错误:名为“app”的工作区不包含名为“app”的方案
- leaflet - 如何在传单地图上的移动标记上获得 latlng?
- javascript - 如何通过javascript绕过例如标题及其内容和html代码?
- java - 从 3.6 迁移到 4.3 时出现休眠异常
- node.js - 开玩笑不嘲笑 request-promise-native post 方法
- typescript - 为什么我不能使用 typescript 为我的自定义界面扩展 HTMLElement 类型?
- salesforce - 从顶点类调用批处理
- imagemagick - 使用 Elixir Mogrify 向图像添加文本
- html - .htaccess 文件从 url 中删除 .html 不起作用
- python - 无法使用 wtforms、append_entry() 和 FieldList(FormField()) 更改动态添加的表单字段的标签