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

C# 如何在不关闭流的情况下取消NetworkStream.ReadAsync,c#,.net,asynchronous,async-await,networkstream,C#,.net,Asynchronous,Async Await,Networkstream,我正在尝试使用NetworkStream.ReadAsync()读取数据,但我找不到如何在调用ReadAsync()后取消它。对于后台,NetworkStream由连接的BluetoothClient对象(来自32Feet.NET Bluetooth库)提供给我 下面是我正在尝试的当前GetIt工作代码 int bytesRead; while (this.continueReading) { bytesRead = await this.stream.ReadAsync(this.b

我正在尝试使用NetworkStream.ReadAsync()读取数据,但我找不到如何在调用ReadAsync()后取消它。对于后台,NetworkStream由连接的BluetoothClient对象(来自32Feet.NET Bluetooth库)提供给我

下面是我正在尝试的当前GetIt工作代码

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行为,因此该令牌被忽略(请参阅)

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


有什么建议吗?

您可以在NetworkStream.Read(或ReadAsync)周围实现一个异步包装器,该包装器还接收一个cancellationtoken,您可以监视并尊重自己。大概是这样的:

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

 ....

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

....

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

请注意,我只是试图说明这个想法,您可能不会考虑返回<代码>任务<代码>,以及是否在循环中拥有DO {}、任何额外的处理或清理等-全部根据您的需要。


我还要提醒您注意Stephen Toub的文章以及他在文章中创建的WithCancellation扩展。

您不能取消ReadAsync,因为内部调用是非托管的,并且使用IOCompletion端口。。你的选择如下

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

  • 我通过让任务在异步调用和wait语句之间等待取消令牌调用来管理取消,如下所示:

    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);
    }
    
    try {
    
     ....
    
     Task<int> readTask = input.ReadAsync(buffer, 0, buffer.Length);
     readTask.Wait(myCancellationToken);
     int readBytes= await readTask;
    
    ....
    
    }
    catch ( OperationCanceledException e )
    {
       // handle cancellation
    }
    
    试试看{
    ....
    Task readTask=input.ReadAsync(buffer,0,buffer.Length);
    readTask.Wait(myCancellationToken);
    int readBytes=等待读取任务;
    ....
    }
    捕捉(操作取消异常e)
    {
    //手柄取消
    }
    
    我忘了检查可用数据!感谢您提供示例代码和Stephen Toub文章的链接。两者都将有助于我实现我所追求的目标。谢谢不幸的是,我没有使用套接字,所以我不相信我可以使用Socket.Shutdown。我创建了一个BluetoothClient(从32Feet.NET)并调用BluetoothClient.Connect()。连接后,我通过BluetoothClient.GetStream()检索流。至于超时,MSDN说流的超时只适用于同步读取()——通过设置ReadTimeout属性确认,ReadAsync()从未超时。不过,关于检查套接字中可用数据的部分很有帮助,这是我完全忘记的。谢谢,我的阅读理解能力不好。我很高兴听到我的非相关答案仍然有用。如果使用TCPClient,TCPClient.Close()方法可用于在挂起的readAsync()调用上引发异常。您是否将此方法用于NetworkStream readAsync和WriteAsync?你能为两者提供一个很好的例子吗?感谢对
    Wait
    的调用阻塞了线程,消除了使用
    ReadAsync
    的好处。