Как отменить 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.. Ваши варианты следующие.
- Использовать Сокет.Выключение.)( Это вернет ReadAsync с ошибкой сокета OperationAborted.
- дождитесь тайм-аута чтения.
- Проверьте, доступны ли данные перед чтением из сокета.
Я управляю отменой, заставляя задачу ждать вызова токена отмены между асинхронным вызовом и оператором await следующим образом:
try {
....
Task<int> readTask = input.ReadAsync(buffer, 0, buffer.Length);
readTask.Wait(myCancellationToken);
int readBytes= await readTask;
....
}
catch ( OperationCanceledException e )
{
// handle cancellation
}