Search code examples
c#androidxamarinmqtt

How to debug connection to MQTT server using Xamarin System.Net.Mqtt on Android?


I'm trying to build a simple MQTT application using Xamarin, and testing it on both an Android emulator and a phone. Unfortunately, I'm struggling to make a connection with CreateAsync, and at a loss how to debug it.

I've checked I can connect to my RabbitMQ server as follows:

using System.Net.Mqtt;
Console.WriteLine("Trying to connect...");
var configuration = new MqttConfiguration();
var client = MqttClient.CreateAsync("127.0.0.1", configuration).Result;
var sessionState = await client.ConnectAsync(new MqttClientCredentials(clientId: "test", userName:"mqtt", password:"mqtt"));
Console.WriteLine("...it worked.");
Console.Read();

As the code tells me... it worked. :o) RabbitMQ shows the connection. I tried it with "localhost", the hostname and IP of my PC to check they all work, and an incorrect host name to see what exception gets thrown ("Socketexception: No such host is known").

My troubles start when I try to do this in the actual app. The connection code is fundamentally the same, but run in a separate task as I read you shouldn't do it in the GUI thread:

    private async Task<SessionState> Connect(string BrokerHostName, Action<MqttApplicationMessage> publishEventHandler)
    {
        MqttConfiguration config = new MqttConfiguration();
        _client = MqttClient.CreateAsync(BrokerHostName, config).Result;
        SessionState sessionState = await _client.ConnectAsync(
            new MqttClientCredentials(clientId: Id, userName: "mqtt", password: "mqtt")
            );

        await _client.SubscribeAsync("common", MqttQualityOfService.AtMostOnce);

        _client.MessageStream.Subscribe(publishEventHandler);
        return sessionState;
    }

Called by:

    var task = Connect(BrokerHostName, publishEventHandler);

But nothing happens - the code reaches this line and just hangs. If I set a break, continuing just continues to do nothing. I've made sure the INTERNET and ACCESS_NETWORK_STATE permissions are ticked in the Android manifest (though it makes no apparent difference).

This is what I've tried after some hours of Googling:

  • Using the hostname or IP address of my PC with the Android device, running with and without debug, and also unplugged from PC and run on its own.
  • Using 10.0.2.2 and running on the emulator, as I understand this is the equivalent of localhost or 127.0.0.1.
  • Setting the proxy address on the emulator to the same as my PC and port 1883. Even though the 'Apply' button teases with a "Proxy status: success", it still doesn't connect.

It feels like a networking problem since I can put any old rubbish as the host address and it behaves the same, but I've totally run out of ideas for what to try next or how to see what's going on. Any advice very gratefully received!


Solution

  • I now have this working. Here's the steps I took, in case it helps someone else:

    1. I wrote some test apps to check TCP communication. First a client and server in Windows to check they work, then a Xamarin client app. This worked and proved the network connections were OK.
    2. Installed an MQTT Tester on the Android emulator to prove it was possible to connect to RabbitMQ.
    3. Tried a different MQTT framework: MQTTnet.

    Similar problem but different symptoms: the code would get stuck on the .Wait() rather than inside the task itself. Then I removed all the asynchronous code and then it connected.

    My conclusion is that the problem may be my lack of understanding of asynchronous programming. System.Net.Mqtt seems to require it while MQTTnet does not, so all's well that ends well!