[英]How can I cancel LoadAsync() without closing the underlying socket?
我有一個應用程序可以通過藍牙上的 rfcomm 與某些硬件進行通信。 我的應用程序在 Android 上運行,並且正在讓事情在 UWP 上運行。 以下是我在 UWP 代碼中設置 stream 讀/寫器的方法:
var btDevice = await BluetoothDevice.FromIdAsync(devId);
var services = await btDevice.GetRfcommServicesAsync();
if (services.Services.Count > 0)
{
// We only have one service so use the first one...
var service = services.Services[0];
// Create a stream...
_bluetoothStream = new StreamSocket();
await _bluetoothStream.ConnectAsync(service.ConnectionHostName, service.ConnectionServiceName);
_dataReader = new DataReader(_bluetoothStream.InputStream);
_dataWriter = new DataWriter(_bluetoothStream.OutputStream);
_dataReader.InputStreamOptions = InputStreamOptions.Partial;
我的硬件僅在應用程序發送數據后才向我的應用程序發送數據,因此我設置了發送/接收機制。 除了我的設備正在重新啟動(但藍牙連接仍然處於活動狀態)並且無法發送響應的特定用例之外,一切都很好。 在這種情況下,我的上層代碼設置為嘗試重試,但是當接收超時時藍牙連接會關閉。
_dataWriter.WriteBytes(comm.TransmitData);
Task<UInt32> writeAysncTask = _dataWriter.StoreAsync().AsTask();
UInt32 bytesWritten = await writeAysncTask;
:
try
{
using (var cts = new CancellationTokenSource(TimeSpan.FromMilliseconds(comm.TimeoutMs))) // _receiveTimeoutMs)))
{
// When this times out, exception gets thrown and socket is closed
// How do I prevent the socket from closing so I can do a retry???
var loadTask = _dataReader.LoadAsync(comm.ReceiveCount).AsTask(cts.Token);
bytesRead = await loadTask;
if (bytesRead > 0)
{
rxData = new byte[bytesRead];
_dataReader.ReadBytes(rxData);
}
else
{
System.Diagnostics.Debug.WriteLine("Received 0!");
}
}
}
catch (Exception ex)
{
// The bluetooth connection is closed automatically if the
// caancellationToken fires...In my case, I need the connection
// to stay open...How do I achieve this???
// Update: When this code is executed with _dataReader/Writer
// that was created with SerialDevice class (see below), the
// timeout exception does not cause the Serial connection to
// close so my calling code can then issue a retry.
System.Diagnostics.Debug.WriteLine(ex.Message) ;
}
更新:應該注意的是,當我對從 SerialDevice 創建的流使用完全相同的代碼時,一切都會按我的預期工作......當接收超時時,套接字不會關閉。 似乎我在 UWP 的藍牙實現中遇到了一些問題。 啊。 以下是我使用 SerialDevice class 創建 _dataReader/_dataWriter 的方法:
_serialDevice = await SerialDevice.FromIdAsync(devId);
// Configure the port
_serialDevice.BaudRate = _baudrate;
_serialDevice.Parity = SerialParity.None;
_serialDevice.DataBits = 8;
_serialDevice.StopBits = SerialStopBitCount.One;
_dataReader = new DataReader(_serialDevice.InputStream);
_dataWriter = new DataWriter(_serialDevice.OutputStream);
我想出了一個解決我面臨的問題的方法。 不幸的是,我不能對 SerialDevice 和 BluetoothDevice 使用相同的代碼。 我不得不說,當取消令牌超時時,藍牙套接字被關閉真的很臭。 如果它沒有關閉,代碼會更干凈嗎? 難道不應該由我來決定是否應該關閉套接字:現在我堅持這個:
using (var cts = new CancellationTokenSource())
{
Task.Run(async () =>
{
try
{
await Task.Delay((int)comm.TimeoutMs, cts.Token);
System.Diagnostics.Debug.WriteLine("Canceling async read");
// If we make it this far, then the read as failed...cancel the async io
// which will cause the bytesRead below to be 0.
await _bluetoothStream.CancelIOAsync();
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
}, cts.Token);
var loadTask = _dataReader.LoadAsync(comm.ReceiveCount).AsTask();
bytesRead = await loadTask;
if (bytesRead > 0)
{
// SIgnal the delay task to cancel...
cts.Cancel(true);
if (bytesRead > comm.ReceiveCount)
System.Diagnostics.Debug.WriteLine("Received too much!!");
rxData = new byte[bytesRead];
_dataReader.ReadBytes(rxData);
}
else
{
System.Diagnostics.Debug.WriteLine("Received 0!");
}
}
實施此操作后,我注意到在配對我的 BT 設備后,Windows 在以下查詢中將其作為 SerialDevice 返回:
string aqs = SerialDevice.GetDeviceSelector();
DeviceInformationCollection devices = await DeviceInformation.FindAllAsync(aqs);
// My bluetooth device is included in the 'devices' collection
因此,如果我將它作為串行設備連接到它,我想我畢竟不需要解決這個問題。 哦,好吧,希望這篇文章對其他人有所幫助。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.