Как определить, когда PipeReader достиг конца источника данных (конец канала)? - PullRequest
1 голос
/ 25 сентября 2019

Мы можем вызвать ReadAsync () и проверить буфер на наличие байтов для чтения ...

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

Если длина не увеличивается с момента до вызова ReadAsync, указывает ли это на конец канала (нет больше байтов для чтения)?Если нет, то каков правильный способ определения «конца канала»?

Мы можем сигнализировать потребление байтов в буфере следующим образом:

reader.AdvanceTo(count);

И затем проверить, есть линеиспользованные байты или возможность предоставления будущих байтов (т. е. производитель еще не сообщил, что прекратил добавлять новые байты в канал)

readResult.IsCompleted

Но если я ищу последовательность (или последовательности) в буфере и ожидает полной последовательности перед ее использованием, тогда IsComplete остается ложным, даже когда буфер содержит все доступные байты, и производитель сообщил о завершении.

Спасибо.

1 Ответ

1 голос
/ 25 сентября 2019

.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
    }
}
...