如何在不关闭流的情况下取消NetworkStream.ReadAsync

我试图使用NetworkStream.ReadAsync()来读取数据,但我无法找到如何在调用时取消ReadAsync()。 对于后台,NetworkStream由连接的BluetoothClient对象(来自32Feet.NET蓝牙库)提供给我。

我正在尝试的当前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,底层蓝牙连接也被关闭。 理想情况下,我不想完全切断与设备的连接只是为了停止阅读。 它似乎不是一种干净的方式,并且感觉不必拆除整个流只是为了中断va ReadAsync()调用。

任何建议?

您可以在NetworkStream.Read(或ReadAsync)周围实现异步包装,它还会收到您可以监控并自己尊重的canceltoken。 像这样的东西:

 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 ,以及是否有do {} while循环,任何额外的处理或清理等等 – 都根据你的需要。

我还要注意Stephen Toub的文章如何取消不可取消的异步操作? 以及他在那里创建的WithCancellation扩展。

您无法取消ReadAsync,因为内部调用是非托管的并且使用IOCompletion端口。您的选项如下所示。

  1. 使用Socket.Shutdown()。 这将返回ReadAsync,套接字错误为OperationAborted。
  2. 等待读取超时。
  3. 在从sockets读取数据之前检查数据是否可用。

我通过让Task等待异步调用和await语句之间的取消令牌调用来管理取消,如下所示:

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