tencent cloud

Using the Client to Subscribe Messages
Last updated:2026-01-30 14:55:29
Using the Client to Subscribe Messages
Last updated: 2026-01-30 14:55:29
MQTT (Message Queuing Telemetry Transport) is a lightweight IoT messaging protocol based on the publish/subscribe (Pub/Sub) model. In the MQTT communication model, a Subscription is the core mechanism by which a client (subscriber) expresses to the server (Broker) its desire to receive messages for a specific topic or a category of topics.

publish/subscribe model

Publishers send messages to a specific Topic, and the Broker forwards the messages to all subscribers subscribed to that Topic.
For example, in the following scenario, the temperature sensor publishes temperature readings to the "temperature" topic. Both the mobile phone and backend business systems subscribing to this topic will receive the complete data set published by the temperature sensor.


Subscription Principle

1. Establishing a connection: The client first establishes a TCP connection with the MQTT Broker and sends a CONNECT packet for authentication.
2. Initiating a subscription: After a successful connection, the client sends a SUBSCRIBE packet to the Broker. This packet contains one or more Topic Filters it wishes to subscribe to, along with the corresponding Quality of Service (QoS) level.
3. Confirming the subscription: Upon receiving the SUBSCRIBE packet, the Broker replies with a SUBACK subscription acknowledgment packet. This packet contains the granted QoS level for each requested Topic Filter subscription (which may be either the level requested by the client or a level granted by the Broker based on its own policy).
4. Message routing: After that, whenever a message is published to a Topic matching that Topic Filter, the Broker will immediately forward the message to that client.
5. Unsubscribing: When a client no longer wishes to receive messages for certain Topics, it sends an UNSUBSCRIBE packet, and the Broker subsequently stops forwarding the relevant messages.

Topic Filters and Wildcards

The Topic Filter used by the client for subscription is not a fully specified Topic name, but one that incorporates wildcards, enabling it to flexibly subscribe to multiple Topics.
Wildcard
Description
Example
+
A single-level wildcard, representing matching exactly one arbitrary topic level.
Subscribe to sensor/+/temperature
Match sensor/bedroom/temperature
Match sensor/living_room/temperature
Does not match sensor/bedroom/upstairs/temperature (because + can only match one level).
sensor/temperature is not matched (because there is a missing level between sensor and temperature).
#
A multi-level wildcard, representing matching zero or more arbitrary topic levels, must be the last character of the topic filter.
Subscribe to sensor/bedroom/#
Match sensor/bedroom/temperature
Match sensor/bedroom/humidity
Match sensor/bedroom/light/intensity
Match sensor/bedroom (# can match zero levels).
sensor/living_room/temperature is not matched (because bedroom is fixed).

Service Quality (QoS)

QoS (Quality of Service) refers to the service quality of message transmission. Each message can have its QoS set individually during sending. It includes the following levels:
QoS Level
Workflow
Advantage
Disadvantages
Scenarios
QoS = 0
(At most once)
The sender sends the message without requiring acknowledgment from the receiver.
The transmission speed is the fastest and the overhead is the lowest.
Messages may be lost in cases such as network failures or when the receiver is offline.
Non-critical data that can tolerate occasional loss, such as periodic sensor data (temperature, humidity), where a lost data point will soon be replaced by the next one.
QoS = 1
(At least once)
1. The sender sends the message and retains a copy.
2. Upon receiving the message, the recipient must reply with a PUBACK (Publish Acknowledgment) packet.
3. The sender will only discard the message copy after the PUBACK is received.
4. If the sender does not receive PUBACK within a reasonable time, it will resend the message.
Ensures that messages are not lost.
This may result in message duplication.
Guaranteed message delivery is required, and occasional duplication is acceptable. For example, control commands ( "turning on/off lights" ) may still function correctly even if they are executed more than once.
QoS = 2
(Exactly once)
1. PUBLISH: The sender sends the message and retains a copy.
2. PUBREC: Upon receipt, the recipient replies with a "received" acknowledgment. If the sender does not receive PUBREC, it will resend the PUBLISH.
3. PUBREL: Upon receiving PUBREC, the sender transmits a "Publish Release" message and can discard the message copy. It now only needs to await final confirmation.
4. PUBCOMP: Upon receiving PUBREL, the recipient replies with a "Publish Complete" acknowledgment. Only then is the message delivered to the application. The sender concludes the process upon receiving PUBCOMP. If either party fails to receive a response, they will resend the previous packet.
Ensures that messages are not lost while guaranteeing non-duplication.
The speed is the slowest and the overhead is the highest.
For mission-critical operations that demand extremely high reliability and accuracy, such as billing systems, financial transactions, and critical state synchronization, any duplication or loss would lead to serious consequences.

Retained Messages

When publishing a message, you can set the retained parameter to true. The Broker will then store the latest retained message for this Topic.
When a new client subscribes to a matching Topic, the Broker immediately sends this latest retained message to it without waiting for its next publish. This is very useful for obtaining the latest device status.
For example, a temperature sensor publishes the current temperature every hour and sets it as a retained message. Any newly connected client subscribing to sensor/temperature will immediately receive the latest temperature without waiting for the next hour.

Usage Examples

package com.tencent.tdmq.mqtt.example.paho.v5;

import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.eclipse.paho.mqttv5.client.IMqttToken;
import org.eclipse.paho.mqttv5.client.MqttCallback;
import org.eclipse.paho.mqttv5.client.MqttClient;
import org.eclipse.paho.mqttv5.client.MqttConnectionOptions;
import org.eclipse.paho.mqttv5.client.MqttDisconnectResponse;
import org.eclipse.paho.mqttv5.client.persist.MemoryPersistence;
import org.eclipse.paho.mqttv5.common.MqttException;
import org.eclipse.paho.mqttv5.common.MqttMessage;
import org.eclipse.paho.mqttv5.common.packet.MqttProperties;
import org.eclipse.paho.mqttv5.common.packet.UserProperty;

public class SubscriberQuickStart {
public static void main(String[] args) throws MqttException, InterruptedException {
// Get the access point from the MQTT console:
// For users who implement VPC network integration via Private Link, use private network access point;
// For users accessing over the public network, ensure the public network security policy permits access, and the machine running the program has public network connectivity;
String serverUri = "tcp://mqtt-xxx.mqtt.tencenttdmq.com:1883";

// A valid Client Identifier contains digits 0-9, lowercase English letters a-z, and uppercase English letters A-Z, with a total length of 1-23 characters
// See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901059
String clientId = "SubscriberQuickStart";

// On the console --> Create account on the Authentication Tab, copy username and password
String username = "user0";
String password = "secret0";

// MQTT topic filters
String[] topicFilters = new String[]{"home/test", "home/#", "home/+"};
int[] qos = new int[]{1, 1, 1};

MqttClient client = new MqttClient(serverUri, clientId, new MemoryPersistence());
client.setTimeToWait(3000);
MqttConnectionOptions options = new MqttConnectionOptions();
options.setUserName(username);
options.setPassword(password.getBytes(StandardCharsets.UTF_8));
options.setCleanStart(true);
options.setAutomaticReconnect(true);

client.setCallback(new MqttCallback() {
@Override
public void disconnected(MqttDisconnectResponse response) {
System.out.println("Disconnected: " + response.getReasonString());
}

@Override
public void mqttErrorOccurred(MqttException e) {
e.printStackTrace();
}

@Override
public void messageArrived(String topic, MqttMessage message) {
byte[] payload = message.getPayload();
String content;
if (4 == payload.length) {
ByteBuffer buf = ByteBuffer.wrap(payload);
content = String.valueOf(buf.getInt());
} else {
content = new String(payload, StandardCharsets.UTF_8);
}

System.out.printf("Message arrived, topic=%s, QoS=%d content=[%s]%n",
topic, message.getQos(), content);
List<UserProperty> userProperties = message.getProperties().getUserProperties();
printUserProperties(userProperties);
}

@Override
public void deliveryComplete(IMqttToken token) {
System.out.println("Delivery complete for packet-id: " + token.getMessageId());
}

@Override
public void connectComplete(boolean reconnect, String serverURI) {
System.out.println(reconnect ? "Reconnected" : "Connected" + " to " + serverURI);
try {
// Subscribe
IMqttToken token = client.subscribe(topicFilters, qos);
int[] reasonCodes = token.getReasonCodes();
for (int i = 0; i < reasonCodes.length; i++) {
System.out.printf("Subscribed to topic %s with QoS=%d, Granted-QoS: %d%n",
topicFilters[i], qos[i], reasonCodes[i]);
}

if (token.isComplete()) {
List<UserProperty> userProperties = token.getResponseProperties().getUserProperties();
printUserProperties(userProperties);
}
} catch (MqttException e) {
e.printStackTrace();
}
}

@Override
public void authPacketArrived(int i, MqttProperties properties) {
System.out.println("Received auth packet with id: " + i);
}
});

client.connect(options);

TimeUnit.MINUTES.sleep(5);

client.disconnect();

client.close();

}

static void printUserProperties(List<UserProperty> userProperties) {
if (null != userProperties) {
for (UserProperty userProperty : userProperties) {
System.out.printf("User property: %s = %s%n", userProperty.getKey(), userProperty.getValue());
}
}
}
}

Was this page helpful?
You can also Contact Sales or Submit a Ticket for help.
Yes
No

Feedback