2013-03-07 3 views
10

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

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

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 установлен в ложь и данные поступают, но пока данные получены не будет проходить мимо линии ReadAsync(). Я не вижу, как прервать вызов без получения данных.

Я знаю, что есть перегрузка ReadAsync, которая предоставляет CancellationToken, но кажется, что, поскольку NetworkStream не переопределяет поведение ReadAsync по умолчанию, токен игнорируется (см. NetworkStream.ReadAsync with a cancellation token never cancels).

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

Любые советы?

ответ

1

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

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); 
} 

Пожалуйста, обратите внимание, что я только пытаюсь проиллюстрировать эту идею, и вы могли бы Wnt рассмотреть вопрос о возвращении Task<TResult>, а также иметь ли Д.О. {} в то время как петли, какой-либо дополнительной обработки или очистки, и т. д. - все в соответствии с вашими потребностями.

Я также хотел бы обратить ваше внимание на статью Стивена Туба How do I cancel non-cancelable async operations? и расширение WithCancellation, которое он создает там.

+0

я забыл о проверке DataAvailable! Спасибо за образец кода и за ссылку на статью Стивена Тууба. Оба будут полезны для меня, чтобы добиться того, что я после. Благодаря! – Swampie

8

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

  1. Использование Socket.Shutdown(). Это вернет ReadAsync с ошибкой сокета OperationAborted.
  2. Подождите, пока прочитайте таймаут.
  3. Проверьте, доступны ли данные перед чтением из гнезда.
+0

К сожалению, я не пользуюсь сокетами, поэтому я не считаю, что могу использовать Socket.Shutdown. Я создаю BluetoothClient (от 32Feet.NET) и вызываю BluetoothClient.Connect(). После подключения я получаю поток через BluetoothClient.GetStream(). Что касается тайм-аута, MSDN говорит, что тайм-аут Stream применяется только для синхронного Read() - подтверждается установкой свойства ReadTimeout, а ReadAsync() никогда не истекает.Немного о проверке данных, доступных из сокета, полезно, хотя и что-то, о чем я совсем забыл. Спасибо – Swampie

+0

Мое понимание чтения провалило меня. Я рад слышать, что мой несвязанный ответ все еще помог. –

+0

При использовании TCPClient метод TCPClient.Close() может использоваться для создания исключения при вызове readAsync(). –

2

Я управляю отменой имея Целевой ждать отмен маркеров вызова между вызовом асинхронного и ждут заявлений, как это:

try { 

.... 

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

.... 

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