Tous les produits
Search
Centre de documentation

ApsaraMQ for MQTT:Send and receive messages between MQTT clients by using the Java SDK

Dernière mise à jour :Oct 09, 2026

Lorsque des appareils IoT ou des applications mobiles doivent échanger des messages directement sans intermédiaire backend, connectez l'éditeur et l'abonneur en tant que clients ApsaraMQ for MQTT. Chaque client utilise le SDK Eclipse Paho Java pour se connecter au broker ApsaraMQ for MQTT via Internet, publier des messages sur un topic et recevoir les messages des topics auxquels il est abonné.

Messaging between clients

Prérequis

Avant de commencer, assurez-vous d'avoir :

Endpoints

Lorsqu'un client ou un service cloud communique avec ApsaraMQ for MQTT, spécifiez l'endpoint de votre instance ApsaraMQ for MQTT dans le code du SDK. Le format de l'endpoint dépend du type de SDK et de votre méthode d'accès réseau.

Format d'endpoint du SDK client

Lorsque vous vous connectez via le SDK client, utilisez les formats d'endpoint suivants :

Méthode d'accès Format d'endpoint Cas d'utilisation typique
Public (Internet) <instance-id>.mqtt.aliyuncs.com Appareils IoT, applications mobiles
VPC (réseau privé) <instance-id>-internal-vpc.mqtt.aliyuncs.com Applications backend dans le cloud

Format d'endpoint du SDK cloud

Lorsque vous vous connectez via le SDK cloud, utilisez les formats d'endpoint suivants :

Important

Seules les instances dont la région se trouve en Chine continentale prennent en charge l'accès via le SDK cloud.

Méthode d'accès Format d'endpoint
Public (Internet) <instance-id>-server-internet.mqtt.aliyuncs.com
VPC (réseau privé) <instance-id>-server-internal.mqtt.aliyuncs.com

Vous pouvez également trouver l'endpoint du SDK client dans l'onglet Endpoints de la page Instance Details dans la console ApsaraMQ for MQTT. L'ID d'instance s'affiche dans la section Basic Information.

Important

Utilisez toujours le nom de domaine, et non une adresse IP. Les adresses IP peuvent changer sans préavis lors de la mise à jour de la résolution des noms de domaine. Alibaba Cloud n'est pas responsable des échecs de connexion causés par des adresses IP codées en dur ou des règles de pare-feu basées sur les IP.

Étape 1 : Ajouter les dépendances Maven

Clonez ou téléchargez le projet de démonstration, puis vérifiez que le fichier pom.xml inclut les dépendances suivantes :

<dependencies>
    <!-- Eclipse Paho: MQTT 3.1.1 client library -->
    <dependency>
        <groupId>org.eclipse.paho</groupId>
        <artifactId>org.eclipse.paho.client.mqttv3</artifactId>
        <version>1.2.2</version>
    </dependency>
    <!-- Commons Codec: HMAC signature calculation for authentication -->
    <dependency>
        <groupId>commons-codec</groupId>
        <artifactId>commons-codec</artifactId>
        <version>1.10</version>
    </dependency>
    <!-- Apache HttpClient: HTTP requests for token-based auth -->
    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.5.2</version>
    </dependency>
    <!-- Fastjson: JSON parsing for API responses -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.83</version>
    </dependency>
    <!-- Alibaba Cloud SDK for MQTT: server-side API calls -->
    <dependency>
        <groupId>com.aliyun</groupId>
        <artifactId>aliyun-java-sdk-onsmqtt</artifactId>
        <version>1.0.3</version>
    </dependency>
    <!-- Alibaba Cloud Core SDK: shared SDK infrastructure -->
    <dependency>
        <groupId>com.aliyun</groupId>
        <artifactId>aliyun-java-sdk-core</artifactId>
        <version>4.5.0</version>
    </dependency>
</dependencies>

Pour le code source et la documentation du client Eclipse Paho Java, consultez Eclipse Paho Java Client.

Étape 2 : Définir les variables d'environnement

Stockez votre paire AccessKey dans des variables d'environnement afin d'éviter toute exposition accidentelle des identifiants dans le code source.

export MQTT_AK_ENV=<your-access-key-id>
export MQTT_SK_ENV=<your-access-key-secret>
Espace réservé Description Exemple
<your-access-key-id> ID AccessKey issu de la console RAM LTAI5tXxx
<your-access-key-secret> Secret AccessKey issu de la console RAM xXxXxXx
Important

Utilisez la paire AccessKey d'un utilisateur RAM plutôt que celle du compte Alibaba Cloud. La paire AccessKey du compte Alibaba Cloud accorde l'accès à toutes les opérations API et présente un risque de sécurité en cas de fuite. Pour plus de détails, consultez Configurer un identifiant d'accès.

Étape 3 : Définir les paramètres de connexion

Définissez les paramètres suivants en fonction des ressources que vous avez créées dans la console ApsaraMQ for MQTT :

// Instance ID from the console's Basic Information section
String instanceId = "<your-instance-id>";

// Endpoint from the console's Endpoints tab
String endPoint = "<your-instance-id>.mqtt.aliyuncs.com";

// Credentials from environment variables
String accessKey = System.getenv("MQTT_AK_ENV");
// The AccessKey secret is required for signature authentication mode
String secretKey = System.getenv("MQTT_SK_ENV");

// Client ID format: GroupID@@@DeviceID (max 64 characters)
// Each TCP connection must use a unique client ID.
// Duplicate client IDs cause connection conflicts and unexpected disconnections.
String clientId = "<your-group-id>@@@<your-device-id>";

// Parent topic created in the console
final String parentTopic = "<your-parent-topic>";

// Subtopic for message filtering (max 128 characters total)
final String mq4IotTopic = parentTopic + "/" + "testMq4Iot";

// QoS level: 0 (at most once), 1 (at least once), or 2 (exactly once)
final int qosLevel = 0;
Remarque

Si le client publie ou s'abonne à un topic qui n'existe pas ou auquel il n'est pas autorisé à accéder, le broker ferme immédiatement la connexion.

Étape 4 : Créer le client MQTT et enregistrer les callbacks

Enregistrez les callbacks avant la connexion. Si vous enregistrez les callbacks après l'appel à connect(), vous risquez de manquer des messages, notamment lors de la reprise d'une session persistante.

Créez le client MQTT :

ConnectionOptionWrapper connectionOptionWrapper =
    new ConnectionOptionWrapper(instanceId, accessKey, secretKey, clientId);

final MemoryPersistence memoryPersistence = new MemoryPersistence();

// Protocol and port must match:
//   TCP  -> tcp://endpoint:1883
//   SSL  -> ssl://endpoint:8883
final MqttClient mqttClient = new MqttClient(
    "tcp://" + endPoint + ":1883", clientId, memoryPersistence);

// Timeout for waiting on broker responses (milliseconds)
mqttClient.setTimeToWait(5000);

final ExecutorService executorService = new ThreadPoolExecutor(
    1, 1, 0, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());

Configurez les callbacks d'événements pour gérer les événements de connexion et les messages entrants :

mqttClient.setCallback(new MqttCallbackExtended() {
    @Override
    public void connectComplete(boolean reconnect, String serverURI) {
        // Subscribe immediately after each connection (including reconnections)
        System.out.println("connect success");
        executorService.submit(() -> {
            try {
                final String[] topicFilter = {mq4IotTopic};
                final int[] qos = {qosLevel};
                mqttClient.subscribe(topicFilter, qos);
            } catch (MqttException e) {
                e.printStackTrace();
            }
        });
    }

    @Override
    public void connectionLost(Throwable throwable) {
        throwable.printStackTrace();
    }

    @Override
    public void messageArrived(String topic, MqttMessage mqttMessage) throws Exception {
        // Process incoming messages here.
        // Do not throw exceptions from this callback. The broker treats a
        // normally returned callback as message acknowledgment.
        // Implement deduplication to ensure idempotent consumption.
        System.out.println(
            "receive msg from topic " + topic + " , body is "
            + new String(mqttMessage.getPayload()));
    }

    @Override
    public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
        System.out.println("send msg succeed topic is : "
            + iMqttDeliveryToken.getTopics()[0]);
    }
});

Comportements clés des callbacks :

Callback Comportement
connectComplete Appelé à chaque connexion, y compris lors des reconnexions automatiques. Réabonnez-vous ici pour restaurer les abonnements.
connectionLost Appelé lorsque la connexion est interrompue. Enregistrez l'erreur ou implémentez une logique de reconnexion.
messageArrived Appelé lorsqu'un message arrive. Ne lancez pas d'exceptions : le broker considère un retour normal du callback comme un accusé de réception. Consommez les messages dans le délai imparti. Implémentez la déduplication pour un traitement idempotent.
deliveryComplete Appelé lorsqu'un message QoS 1 ou QoS 2 est livré.

Étape 5 : Se connecter et publier des messages

Connectez-vous au broker et publiez des messages. Cet exemple envoie à la fois des messages pub/sub normaux et des messages point à point (P2P) :

mqttClient.connect(connectionOptionWrapper.getMqttConnectOptions());

for (int i = 0; i < 10; i++) {
    // Publish a normal message to the subscribed topic
    MqttMessage message = new MqttMessage("hello mq4Iot pub sub msg".getBytes());
    message.setQos(qosLevel);
    mqttClient.publish(mq4IotTopic, message);

    // Publish a P2P message directly to a specific client
    // P2P topic format: {parentTopic}/p2p/{targetClientId}
    // The target client does not need to subscribe to this topic.
    final String p2pSendTopic = parentTopic + "/p2p/" + clientId;
    message = new MqttMessage("hello mq4Iot p2p msg".getBytes());
    message.setQos(qosLevel);
    mqttClient.publish(p2pSendTopic, message);
}

// Keep the client running to continue receiving messages
Thread.sleep(Long.MAX_VALUE);

Messagerie P2P : Lorsque vous connaissez le client cible exact, envoyez un message au topic {parentTopic}/p2p/{targetClientId}. Le client cible reçoit le message sans avoir besoin de s'y abonner. Cela simplifie les scénarios où un message est destiné à un seul destinataire.

Code complet

Le listing suivant combine toutes les étapes ci-dessus en une seule classe exécutable. Il est également disponible dans le projet de démonstration sur GitHub.

package com.aliyun.openservices.lmq.example.demo;

import com.aliyun.openservices.lmq.example.util.ConnectionOptionWrapper;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallbackExtended;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;

public class MQ4IoTSendMessageToMQ4IoTUseSignatureMode {
    public static void main(String[] args) throws Exception {
        // --- Connection parameters ---
        String instanceId = "<your-instance-id>";
        String endPoint = "<your-instance-id>.mqtt.aliyuncs.com";
        String accessKey = System.getenv("MQTT_AK_ENV");
        String secretKey = System.getenv("MQTT_SK_ENV");
        String clientId = "<your-group-id>@@@<your-device-id>";
        final String parentTopic = "<your-parent-topic>";
        final String mq4IotTopic = parentTopic + "/" + "testMq4Iot";
        final int qosLevel = 0;

        // --- Create client ---
        ConnectionOptionWrapper connectionOptionWrapper =
            new ConnectionOptionWrapper(instanceId, accessKey, secretKey, clientId);
        final MemoryPersistence memoryPersistence = new MemoryPersistence();
        final MqttClient mqttClient = new MqttClient(
            "tcp://" + endPoint + ":1883", clientId, memoryPersistence);
        mqttClient.setTimeToWait(5000);

        final ExecutorService executorService = new ThreadPoolExecutor(
            1, 1, 0, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());

        // --- Register callbacks before connecting ---
        mqttClient.setCallback(new MqttCallbackExtended() {
            @Override
            public void connectComplete(boolean reconnect, String serverURI) {
                System.out.println("connect success");
                executorService.submit(() -> {
                    try {
                        final String[] topicFilter = {mq4IotTopic};
                        final int[] qos = {qosLevel};
                        mqttClient.subscribe(topicFilter, qos);
                    } catch (MqttException e) {
                        e.printStackTrace();
                    }
                });
            }

            @Override
            public void connectionLost(Throwable throwable) {
                throwable.printStackTrace();
            }

            @Override
            public void messageArrived(String topic, MqttMessage mqttMessage) throws Exception {
                System.out.println(
                    "receive msg from topic " + topic + " , body is "
                    + new String(mqttMessage.getPayload()));
            }

            @Override
            public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
                System.out.println("send msg succeed topic is : "
                    + iMqttDeliveryToken.getTopics()[0]);
            }
        });

        // --- Connect and publish ---
        mqttClient.connect(connectionOptionWrapper.getMqttConnectOptions());
        for (int i = 0; i < 10; i++) {
            MqttMessage message = new MqttMessage("hello mq4Iot pub sub msg".getBytes());
            message.setQos(qosLevel);
            mqttClient.publish(mq4IotTopic, message);

            final String p2pSendTopic = parentTopic + "/p2p/" + clientId;
            message = new MqttMessage("hello mq4Iot p2p msg".getBytes());
            message.setQos(qosLevel);
            mqttClient.publish(p2pSendTopic, message);
        }
        Thread.sleep(Long.MAX_VALUE);
    }
}

Vérifier les résultats

Après avoir exécuté l'application, interrogez les traces de messages dans la console ApsaraMQ for MQTT pour confirmer que les messages ont été envoyés et reçus. Pour les étapes détaillées, consultez Interroger les traces de messages.

Étapes suivantes