Как отменить NetworkStream.ReadAsync без закрытия потока

Я пытаюсь использовать NetworkStream.ReadAsync() для чтения данных, но я не могу найти, как отменить ReadAsync () после вызова. Для фона NetworkStream предоставляется мне подключенным объектом BluetoothClient (от 32Feet.NET библиотека Bluetooth).

текущий код get-it-working, который я пытаюсь, приведен ниже.

int bytesRead;

while (this.continueReading)
{
    bytesRead = await this.stream.ReadAsync(this.buffer, 0, (int)this.buffer.Length);

    Console.WriteLine("Received {0} bytes", bytesRead);
}

Console.WriteLine("Receive loop has ended");

код отлично работает, получая данные, и прекратит цикл, если флаг continueReading установлен в false и данные получены, но пока данные полученный он не будет проходить мимо строки ReadAsync (). Я не вижу, как прервать вызов без получения данных.

Я знаю, что существует перегрузка ReadAsync, которая предоставляет CancellationToken, но похоже, что, поскольку NetworkStream не переопределяет поведение ReadAsync по умолчанию, токен игнорируется (см. объекте networkstream.ReadAsync с токеном отмены никогда не отменяет).

Я попытался закрыть базовый поток, и это вызывает ожидание вызова ReadAsync для вызова ObjectDisposedException, и базовое соединение Bluetooth также закрывается. В идеале я не хочу полностью разорвать соединение с устройством, чтобы просто прекратить чтение. Это не кажется чистым способом сделать это и чувствует себя ненужным, чтобы сорвать весь поток, чтобы прервать вызов Va ReadAsync ().

какие-либо советы?

3 ответов


вы можете реализовать асинхронную оболочку вокруг NetworkStream.Read (или ReadAsync), который также получает cancellationtoken, который вы можете контролировать и уважать себя. Что-то вроде этого:--3-->

Task MyCancelableNetworkStreamReadAsync(NetworkStream stream, CancellationToken ct)
{
...
if(this.stream.CanRead)
{
  do 
  {
    //check ct.IsCancellationRequested and act as needed
    bytesRead = await this.stream.ReadAsync(this.buffer, 0, (int)this.buffer.Length);
  }
  while(myNetworkStream.DataAvailable);
}

обратите внимание, что я только пытаюсь проиллюстрировать эту идею, и вы можете не рассматривать возможность возвращения Task<TResult>, а также иметь ли цикл do{}while, любую дополнительную обработку или очистку и т. д. - все в соответствии с вашими потребностями.

Я бы также обратил ваше внимание на статья Стивена Туба как отменить асинхронные операции без отмены? и расширение WithCancellation он создает там.


вы не можете отменить ReadAsync, так как внутренний вызов неуправляем и использует порты IOCompletion.. Ваши варианты следующие.

  1. Использовать Сокет.Выключение.)( Это вернет ReadAsync с ошибкой сокета OperationAborted.
  2. дождитесь тайм-аута чтения.
  3. Проверьте, доступны ли данные перед чтением из сокета.

Я управляю отменой, заставляя задачу ждать вызова токена отмены между асинхронным вызовом и оператором await следующим образом:

try {

 ....

 Task<int> readTask = input.ReadAsync(buffer, 0, buffer.Length);
 readTask.Wait(myCancellationToken);
 int readBytes= await readTask;

....

}
catch ( OperationCanceledException e )
{
   // handle cancellation
}