2013-03-07 28 views
10

Tôi đang cố sử dụng NetworkStream.ReadAsync() để đọc dữ liệu nhưng tôi không thể tìm cách hủy bỏ ReadAsync() một lần được gọi. Đối với nền, NetworkStream được cung cấp cho tôi bởi một đối tượng BluetoothClient được kết nối (từ Thư viện Bluetooth 32Feet.NET).Cách hủy NetworkStream.ReadAsync mà không đóng luồng

Mã làm việc hiện tại tôi đang cố gắng ở bên dưới.

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"); 

Mã này hoạt động dữ liệu nhận tốt, và sẽ ngừng lặp nếu cờ continueReading được thiết lập là false và dữ liệu được nhận, nhưng cho đến khi nhận được dữ liệu nó sẽ không tiến hành quá khứ dòng ReadAsync(). Tôi không thể xem cách hủy cuộc gọi mà không nhận dữ liệu.

Tôi biết rằng có quá tải ReadAsync cung cấp CancellationToken, nhưng có vẻ như NetworkStream không ghi đè hành vi ReadAsync mặc định, mã thông báo bị bỏ qua (xem NetworkStream.ReadAsync with a cancellation token never cancels).

Tôi đã thử đóng luồng cơ bản và điều này làm cho cuộc gọi chờ đợi của ReadAsync ném ObjectDisposedException và kết nối Bluetooth bên dưới cũng bị đóng. Lý tưởng nhất là tôi không muốn cắt đứt hoàn toàn kết nối với thiết bị chỉ để dừng đọc. Nó không có vẻ là một cách sạch sẽ để làm điều đó, và cảm thấy không cần thiết để phá vỡ toàn bộ dòng chỉ để làm gián đoạn va ReadAsync() gọi.

Bạn có lời khuyên nào không?

Trả lời

1

Bạn có thể triển khai trình bao bọc không đồng bộ xung quanh NetworkStream.Read (hoặc ReadAsync), cũng nhận được thông báo hủy mà bạn có thể theo dõi và tự nhận mình. Một cái gì đó như thế này:

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

Xin lưu ý rằng tôi chỉ cố gắng để minh họa cho ý tưởng và bạn có thể wnt để xem xét trở Task<TResult>, cũng như liệu có nên có do {} while loop, bất kỳ xử lý bổ sung hoặc dọn dẹp, vv - tất cả theo nhu cầu của bạn.

Tôi cũng sẽ hướng sự chú ý của bạn đến bài viết của Stephen Toub How do I cancel non-cancelable async operations? và tiện ích WithCancellation mà anh ấy tạo ở đó.

+0

tôi muốn quên về việc kiểm tra DataAvailable! Cảm ơn bạn đã gửi mã mẫu và liên kết tới bài viết của Stephen Toub. Cả hai sẽ rất hữu ích cho tôi để đạt được điều đó tôi sau. Cảm ơn! – Swampie

8

Bạn không thể hủy bỏ ReadAsync vì cuộc gọi nội bộ không được quản lý và sử dụng cổng IOCompletion .. Các tùy chọn của bạn như sau.

  1. Sử dụng Socket.Shutdown(). Điều này sẽ trả về ReadAsync với lỗi socket của OperationAborted.
  2. Đợi đọc hết thời gian chờ.
  3. Kiểm tra xem dữ liệu có sẵn trước khi đọc từ ổ cắm hay không.
+0

Rất tiếc, tôi không sử dụng Ổ cắm, vì vậy tôi không tin rằng tôi có thể sử dụng Socket.Shutdown. Tôi tạo một BluetoothClient (từ 32Feet.NET) và gọi BluetoothClient.Connect(). Sau khi kết nối tôi lấy luồng thông qua BluetoothClient.GetStream(). Đối với thời gian chờ, MSDN cho biết thời gian chờ của luồng chỉ áp dụng cho đồng bộ Read() - được xác nhận bằng cách thiết lập thuộc tính ReadTimeout và ReadAsync() không bao giờ hết thời gian chờ.Các bit về kiểm tra dữ liệu có sẵn từ ổ cắm là hữu ích mặc dù, và một cái gì đó tôi hoàn toàn quên về. Cảm ơn – Swampie

+0

Đọc hiểu của tôi không thành công. Tôi rất vui khi biết rằng câu trả lời không liên quan của tôi vẫn giúp ích. –

+0

Nếu sử dụng TCPClient, phương thức TCPClient.Close() có thể được sử dụng để tăng ngoại lệ trên cuộc gọi treo readAsync(). –

2

Tôi đang quản lý việc hủy bỏ bằng cách Task chờ việc hủy bỏ cuộc gọi thẻ giữa các cuộc gọi async và báo cáo kết quả chờ đợi như thế này:

try { 

.... 

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

.... 

} 
catch (OperationCanceledException e) 
{ 
    // handle cancellation 
} 
Các vấn đề liên quan