2013-03-07 129 views
10

我想使用NetworkStream.ReadAsync()来读取数据,但我找不到如何取消一次调用的ReadAsync()。对于后台,NetworkStream由连接的BluetoothClient对象(来自32Feet.NET蓝牙库)提供给我。如何取消NetworkStream.ReadAsync而不关闭流

我正在尝试的当前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()线。我无法看到如何在不接收数据的情况下中止通话。

我知道有一个提供CancellationToken的ReadAsync的重载,但是由于NetworkStream没有覆盖默认的ReadAsync行为,因此该标记被忽略(请参阅NetworkStream.ReadAsync with a cancellation token never cancels)。

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

有什么建议吗?

回答

1

您可以在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); 
} 

请注意,我只是想说明的想法,你可能Wnt信号考虑回国Task<TResult>,以及是否有禁止{} while循环,任何额外的处理或清理,等 - 全部根据您的需求。

我还将您的注意力集中在Stephen Toub的文章How do I cancel non-cancelable async operations?以及他在那里创建的WithCancellation扩展。

+0

我都忘了关于检查DataAvailable!感谢您的示例代码和Stephen Toub文章的链接。两者都将有助于我实现这一目标。谢谢! – Swampie 2013-03-08 09:25:41

8

您不能取消ReadAsync,因为内部呼叫不受管理并使用IOCompletion端口。您的选项如下。

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

不幸的是我没有使用套接字,所以我不相信我可以使用Socket.Shutdown。我创建了一个BluetoothClient(来自32Feet.NET)并调用BluetoothClient.Connect()。一旦连接,我通过BluetoothClient.GetStream()获取流。至于超时,MSDN表示Stream的超时只适用于同步Read() - 通过设置ReadTimeout属性和ReadAsync()确认永不超时。关于从套接字中获取数据的检查很有帮助,而且我完全忘记了一些。谢谢 – Swampie 2013-03-08 09:38:13

+0

我的阅读理解失败了。我很高兴听到我的无关答案仍然有帮助。 – 2013-03-08 18:55:02

+0

如果使用TCPClient,则可以使用TCPClient.Close()方法在悬挂的readAsync()调用上引发异常。 – 2017-11-27 22:05:12

2

我感到有任务等待异步调用和等待语句像这样的取消标记呼叫管理取消:

try { 

.... 

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

.... 

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