c# .net asynchronous async-await networkstream

c# - Cómo cancelar NetworkStream.ReadAsync sin secuencia de cierre



.net asynchronous (3)

Estoy tratando de usar NetworkStream.ReadAsync () para leer datos, pero no puedo encontrar cómo cancelar ReadAsync () una vez que se llama. Como fondo, NetworkStream me lo proporciona un objeto BluetoothClient conectado (desde 32Feet.NET Bluetooth Library).

El código actual de "hazlo funcionar" que estoy intentando está debajo.

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

El código funciona bien al recibir datos, y dejará de repetirse si el indicador continueReading se establece en falso y se reciben los datos, pero hasta que se reciban los datos, no pasarán más allá de la línea ReadAsync (). No veo cómo abortar la llamada sin recibir datos.

Soy consciente de que hay una sobrecarga de ReadAsync que proporciona un CancellationToken, pero parece que como NetworkStream no anula el comportamiento ReadAsync predeterminado, el token se ignora (vea NetworkStream.ReadAsync con un token de cancelación que nunca se cancela ).

Intenté cerrar la transmisión subyacente, y esto hace que la llamada en espera de la lectura de datos arroje ObjectDisposedException, y la conexión Bluetooth subyacente se cierra también. Lo ideal es que no corte completamente la conexión con el dispositivo solo para dejar de leer. No parece una forma clara de hacerlo, y no es necesario cortar toda la secuencia solo para interrumpir la llamada a ReadAsync ().

¿Algún consejo?


Estoy gestionando la cancelación haciendo que la Tarea espere la llamada de token de cancelación entre la llamada asincrónica y la declaración de espera de esta manera:

try { .... Task<int> readTask = input.ReadAsync(buffer, 0, buffer.Length); readTask.Wait(myCancellationToken); int readBytes= await readTask; .... } catch ( OperationCanceledException e ) { // handle cancellation }


No puede cancelar ReadAsync ya que la llamada interna no está administrada y utiliza puertos IOCompletion. Sus opciones son las siguientes.

  1. Use Socket.Shutdown (). Esto devolverá ReadAsync con un error de socket de OperationAborted.
  2. Espere a que termine el tiempo de lectura.
  3. Verifique si los datos están disponibles antes de leer desde el socket.

Puede implementar un contenedor asíncrono alrededor de NetworkStream.Read (o ReadAsync), que también recibe un token de cancelación que puede supervisar y honrar a usted mismo. Algo como esto:

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

Tenga en cuenta que solo estoy tratando de ilustrar la idea y es posible que desee considerar la devolución de Task<TResult> , así como si tiene el ciclo do {} while, cualquier proceso o limpieza adicional, etc., todo según sus necesidades. .

También me gustaría llamar su atención sobre el artículo de Stephen Toub. ¿Cómo puedo cancelar operaciones de sincronización no cancelables? y la extensión WithCancellation que crea allí.