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

Swa*_*pie 12 .net c# asynchronous networkstream async-await

我试图使用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");
Run Code Online (Sandbox Code Playgroud)

代码可以很好地接收数据,并且如果continueReading标志设置为false并且接收到数据,则将停止循环,但是在接收到数据之前,它将不会继续通过ReadAsync()行.我无法看到如何在不接收数据的情况下中止呼叫.

我知道ReadAsync的重载提供了一个CancellationToken,但是当NetworkStream没有覆盖默认的ReadAsync行为时,会忽略该令牌(请参阅具有取消令牌的NetworkStream.ReadAsync永远不会取消).

我尝试关闭底层流,这导致等待ReadAsync调用抛出ObjectDisposedException,底层蓝牙连接也被关闭.理想情况下,我不想完全切断与设备的连接,只是为了停止阅读.它似乎不是一种干净的方式,并且感觉不必拆除整个流只是为了中断va ReadAsync()调用.

有什么建议?

Jam*_*mon 8

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

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


G. *_*nev 4

您可以围绕 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);
}
Run Code Online (Sandbox Code Playgroud)

请注意,我只是想说明这个想法,您可能不想考虑返回Task<TResult>,以及是否有 do{}while 循环、任何额外的处理或清理等 - 一切都根据您的需要。

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