2013-03-07 122 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 
}