ConnectAsync()在C#Visual Studio中永远不会完成

时间:2018-09-06 13:31:49

标签: c# sockets uwp bluetooth rfcomm

TLDR:为运行Windows 10 IoT和StreamSockets.ConnectAsync()(RFCOMM)的Raspberry Pi 3 Model B创建UWP应用有时会完成,并且有时需要花费很长的时间才能失败(“还有更多数据可用。(来自HRESULT的异常:0x80070103)”)或永远无法完成。这是为什么?在Visual Studio中使用调试器没有成功。

我目前正在使用Visual Studio 2017创建UWP应用并用C#编写。该应用已在运行Windows 10 IoT的Raspberry Pi 3 Model B上进行了测试,其目的是使用RFCOMM连接具有HC-06蓝牙模块的Arduino。

我有一个按钮用于测试Raspberry Pi和Arduino之间的连接,它将尝试(依次)连接到我定义的所有蓝牙设备。

但是,我遇到了“错误”;有时,当我单击按钮时,连接测试工作正常,建立了连接,我还可以在Arduino的串行监视器中看到打印的发送数据。 问题是有时对StreamSockets.ConnectAsync()的调用永远不会结束或使用非常长的时间才能失败,但出现以下异常:“没有更多数据可用。(来自HRESULT的异常:0x80070103)”。

我的问题是什么可能导致这种行为?

下面的所有代码都位于Settings.xaml.cs中。

public sealed partial class Settings : Page
{
    private MainPage rootPage = Current;

    private StreamSocket socket = null;
    private DataWriter writer = null;
    private RfcommDeviceService service = null;
    private BluetoothDevice bluetoothDevice;

    public Settings()
    {
        InitializeComponent();
    }

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        rootPage = Current;
    }

    protected override void OnNavigatedFrom(NavigationEventArgs e)
    {
        Disconnect();
    }

    void App_Suspending(object sender, Windows.ApplicationModel.SuspendingEventArgs e)
    {
        Disconnect("App suspension discconects");
    }

// Rest of the code is below here //

}

我的程序流程:

单击按钮后,将调用ConnectionTestButton_Click

private void ConnectionTestButton_Click(object sender, RoutedEventArgs e)
{
    ConnectionTest();
}

依次调用ConnectionTest()

private async void ConnectionTest()
{
    rootPage.NotifyUser("Connection test in progress...", NotifyType.StatusMessage);
    Disconnect(); // Ensures that there is no residue data from previous attempts

  // This connects to the Bluetooth devices I have specified in MainPage.xaml.cs in turn
  // There is no problem with the declaration of the devices as this works correctly
    foreach (KeyValuePair<string, string> device in Constants.BtDevices)
    {
        await Task.Run(() => ConnectToBtDevice(device.Value, true));
        await Task.Delay(5000);
        Disconnect("Connection test");
        await Task.Delay(5000);
    }
}

通话ConnectToBtDevice() x 次,其中 x 由我在MainPage.xaml.cs中声明的蓝牙设备数定义:

private async Task ConnectToBtDevice(string btId, bool connectionTest = false)
{
    try
    {
        bluetoothDevice = await BluetoothDevice.FromIdAsync(btId);
        rootPage.NotifyUser(
                 Constants.BtDevices.FirstOrDefault(x => x.Value == btId).Key
                 + " found, trying to connect...",
                 NotifyType.StatusMessage);
    }
    catch (Exception ex)
    {
        rootPage.NotifyUser(
                 "An exception was thrown when trying to receive the Bluetooth device "
                 + ex.Message,
                 NotifyType.ErrorMessage);
        return;
    }

    if (bluetoothDevice == null)
    {
        rootPage.NotifyUser("Bluetooth device returned null",
                 NotifyType.ErrorMessage);
    }

    var rfcommServices = await bluetoothDevice.GetRfcommServicesAsync();
    if (rfcommServices.Services.Count > 0)
    {
        service = rfcommServices.Services[0];
    }
    else
    {
        rootPage.NotifyUser("No RFCOMM services found on the device",
                 NotifyType.ErrorMessage);
        return;
    }

    lock (this)
    {
        socket = new StreamSocket();
    }
    try
    {
      // This call is what is causing my headache
        await socket.ConnectAsync(service.ConnectionHostName,
                     service.ConnectionServiceName,
                     SocketProtectionLevel
                      .BluetoothEncryptionAllowNullAuthentication);

        rootPage.NotifyUser("Hostname: "
                 + service.ConnectionHostName
                 + " Servicename: "
                 + service.ConnectionServiceName,
                 NotifyType.StatusMessage);

    // Ensure utf8 is used for the reader and writer
    // Not sure if this is actually necessary?
        writer = new DataWriter(socket.OutputStream)
        {
            UnicodeEncoding = UnicodeEncoding.Utf8
        };
        DataReader reader = new DataReader(socket.InputStream)
        {
            UnicodeEncoding = UnicodeEncoding.Utf8
        };

        rootPage.NotifyUser("Connected to "
                 + Constants.BtDevices.FirstOrDefault(x => x.Value == btId).Key,
                 NotifyType.SuccessMessage);

        ReceiveData(reader, connectionTest);

     // Send some data if the connection is for test purposes only
        if (connectionTest)
        {
            await SendData("Test");
        }
    }
    catch (Exception ex)
    {
        rootPage.NotifyUser("An exception was thrown when trying to connect to "
                 + Constants.BtDevices.FirstOrDefault(x => x.Value == btId).Key
                 + " "
                 + ex.Message,
                 NotifyType.ErrorMessage);
        Disconnect();
    }
}

如果已建立连接并且已发送数据,它也会调用Disconnect

private void Disconnect(string disconnectReason = null)
{
    if (writer != null)
    {
        writer.DetachStream();
        writer = null;
    }

    if (service != null)
    {
        service.Dispose();
        service = null;
    }
    lock (this)
    {
        if (socket != null)
        {
            socket.Dispose();
            socket = null;
        }
    }
    if (disconnectReason != null)
    {
        rootPage.NotifyUser("Disconnected. Reason: "
                 + disconnectReason,
                 NotifyType.CautionMessage);
    }
}

(如果有任何代码奇怪地缩进/格式化,则可能是因为我试图限制该问题的行长,所以我在问题文本编辑器中对其进行了快速格式化)

我已经在Visual Studio中尝试了调试器,但是由于一切似乎正常,因此未能成功找到问题所在。通常,我的意思是每个变量都应该是预期的,例如service.ConnectionHostNameservice.ConnectionServiceName均设置为正确的值。 {(XX:XX:XX:XX:XX:XX)}"Bluetooth#BluetoothbX:XX:XX:XX:XX:XX-XX:XX:XX:XX:XX:XX#RFCOMM:XXXXXXXX:{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}"(为了隐私起见“ X”(不是真的那么重要,但是比后悔更安全;)))

SendData()ReceiveData()都与这个问题无关,因为问题在于调用任何一种方法之前,但是如果需要,我会很乐意将它们包括在内。

我还可以补充一点,因为我是UWP开发,网络/蓝牙和C#的新手,所以我使用了BluetoothRfcommChat示例作为参考。

(另外,让我知道问题本身的格式是否有问题)

更新:

有时建立连接的时间太长,我可能会遇到异常:“连接尝试失败,因为一段时间后被连接方未正确响应,或者建立连接失败,因为连接的主机未能响应。 “

更新2:

我添加了CancellationToken来具有ConnectAsync方法的超时功能,但是,ConnectAsync有时仅注册取消请求,这意味着有时它仍然卡住。

我的实现方式:

// Called in constructor
private CancellationTokenSource connectionCts = null;

// Called in 'ConnectoToBtDevice' (same place as original)
try
{
  // public const int ConnectionTimeout = 5000;
    connectionCts = new CancellationTokenSource();
    connectionCts.CancelAfter(Constants.ConnectionTimeout);
    await socket.ConnectAsync(service.ConnectionHostName,
                 service.ConnectionServiceName)
                  .AsTask(connectionCts.Token);

  ...

}
catch (TaskCanceledException tEx)
{
    rootPage.NotifyUser("Connection timed out.", NotifyType.ErrorMessage);
    Disconnect();
}

// Called in 'Disconnect'
if (connectionCts != null)
{
    connectionCts.Dispose();
    connectionCts = null;
}

更新3:

看来,如果我尝试使用:

await bluetoothDevice.GetRfcommAsync(BluetoothCacheMode.Uncached);

(使用BluetoothCacheMode.Uncached)它停留在该行。我不知道这是否与上述问题有关,但可能如此。

更新4:

好的,所以我现在进行了一些测试,发现连接到手机没有问题。这使得使用HC-06模块(UUID =“ {00001101-0000-1000-8000-00805F9B34FB}'”)上的串行端口服务连接时似乎出现问题。问题是这是我的HC-06提供的唯一RFCOMM服务。

0 个答案:

没有答案