如何检测 PipeReader 何时到达数据源的末端(管道末端)?

How to detect when a PipeReader has reached the end of the data source (end of pipe)?

我们可以调用 ReadAsync() 并检查读取字节的缓冲区...

PipeReader reader = ...;
ReadResult readResult = await reader.ReadAsync();
ReadOnlySequence<byte> buffer = readResult.Buffer;
long availableBytes = buffer.Length

如果在调用 ReadAsync 之前长度没有增加,是否表示管道结束(没有更多字节要读取)?如果不是那么检测 'end of pipe' 的正确方法是什么?

我们可以像这样表示缓冲区中字节的消耗:

reader.AdvanceTo(count);

然后检查是否有任何未使用的字节,或者是否有可能提供未来的字节(即生产者尚未发出停止向管道添加新字节的信号)

readResult.IsCompleted

但是如果我在缓冲区中寻找一个序列(或多个序列)并在使用它之前等待一个完整的序列,那么 IsComplete 似乎仍然为假,即使缓冲区包含所有可用字节,并且生产者已发出完成信号。

谢谢。

.IsCompleted 确实表示管道的末端,在套接字等意义上 closed (与打开但没有更多数据权相反)现在);我预计这里发生的是你:

  • 正在获取读取缓冲区
  • 正在读取整个缓冲区以查找序列,但没有找到
  • 因此处理零字节
  • 因此说 .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
    }
}