eehouse
eehouse

Reputation: 23

How to force MQTT broker to NOT clean session from Android Paho client?

I'm trying to use MQTT (Paho library on Android, mosquitto message broker on a linux server) to pass moves in a turn-based game, replacing a custom server I wrote years ago. Its simplicity and pub-sub design seem perfect: each device subscribes to a unique id as "topic" and communicates that as its "address." Then other devices can reach it by publishing to that address.

It works perfectly in my test Linux client (connecting using the mosquitto-dev library on Ubuntu). And it works perfectly on Android WHEN THE ANDROID APP IS RUNNING. In the Linux client case, if a message is sent while the app isn't running or connected the app receives the message as soon as it does connect and subscribe. On Android, however, this doesn't happen. Only messages sent (or resent) by another client while the android client is subscribed are ever delivered.

I'm new to MQTT, but it seems pretty clear that the "cleanSession" connection parameter is what controls this: unless you "clean" a session, you get everything that was published to your topic while you were not subscribed. On the Linux client side, passing "true" to mosquitto_new(..., clean_session, ...) does indeed prevent my Linux client from getting pre-connection messages. But on the Android side, calling .setCleanSession(boolean) has no effect when the MqttConnectOptions instance is passed to .connect().

I'm using 1.1.+ of paho. Per the tags in the repo at https://github.com/eclipse/paho.mqtt.android.git, v1.1.1 is the latest.

implementation "org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.1.+"
implementation "org.eclipse.paho:org.eclipse.paho.android.service:1.1.+"

I suspect that this is simply a bug in the Android Paho library (which doesn't seem to have been worked on in four years.) But I hope I'm wrong! Is there a way to accomplish what I want?

Alternatively, is there a better library? The googling I've done suggests that in spite of its age Paho is still what most Android devs are using to speak MQTT.

Thanks!

Upvotes: 0

Views: 1347

Answers (2)

eehouse
eehouse

Reputation: 23

I've found a workaround, and in the process confirmed my suspicion that the MqttAndroidClient class is broken in not honoring that setting. Instead of using MqttConnectOptions I tried using MqttAsyncClient. The code changes are trivial, though underneath there's considerable change as the Android client knows about and uses background Services. With the simple change of using this different class, I'm able to connect & subscribe and immediately receive all messages that were published while I was not connected.

Upvotes: 0

idan
idan

Reputation: 555

About the cleanSession flag. The Client and Server can store Session state to enable reliable messaging to continue across a sequence of Network Connections. This bit is used to control the lifetime of the Session state.

If CleanSession is set to 0, the Server MUST resume communications with the Client based on state from the current Session (as identified by the Client identifier). If there is no Session associated with the Client identifier the Server MUST create a new Session. The Client and Server MUST store the Session after the Client and Server are disconnected. After the disconnection of a Session that had CleanSession set to 0, the Server MUST store further QoS 1 and QoS 2 messages that match any subscriptions that the client had at the time of disconnection as part of the Session state. It MAY also store QoS 0 messages that meet the same criteria.

More about cleanSession on : https://docs.oasis-open.org/mqtt/mqtt/v3.1.1/csprd02/mqtt-v3.1.1-csprd02.html

If I understand correctly your requirement, then indeed you need to use clenSession=true. You can also try publishing and subscribing with QoS=0. Some brokers do not store QoS=0 messages, mosquitto as well. (as per https://mosquitto.org/man/mqtt-7.html)

Upvotes: 0

Related Questions