如何在不关闭底层套接字的情况下取消 LoadAsync()?



我有一个应用程序,可以通过蓝牙上的rfcomm与某些硬件进行通信。 我的应用程序适用于 Android,并且正在让事情在 UWP 上运行。下面介绍如何在 UWP 代码中设置流读取器/编写器:

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

更新:应该注意的是,当我对从串行设备创建的流使用完全相同的代码时,一切都像我预期的那样工作......当接收超时时,套接字不会关闭。 似乎也许我在 UWP 中的蓝牙实现中遇到了一些东西。 呸。 以下是我如何使用 SerialDevice 类创建 _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);

我想出了解决我面临的问题的方法。 不幸的是,我不能对串行设备和蓝牙设备使用相同的代码。 我不得不说,当取消令牌超时时,蓝牙插座关闭真的很臭。 如果不关闭,代码会干净得多! 是否应该关闭插座不应该由我来决定吗? 现在我被困住了:

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在以下查询中将其作为串行设备返回:

string aqs = SerialDevice.GetDeviceSelector();
DeviceInformationCollection devices = await DeviceInformation.FindAllAsync(aqs);
// My bluetooth device is included in the 'devices' collection

因此,如果我作为串行设备连接到它,我想我根本不需要解决。 哦,好吧,希望这篇文章能帮助其他人。

相关内容

  • 没有找到相关文章