Client MQTT en Java

Client MQTT en Java

1. Vue d'ensemble

Dans ce didacticiel, nous allons voir comment nous pouvons ajouter la messagerie MQTT dans un projet Java en utilisant les bibliothèques fournies par lesEclipse Paho project.

2. Primer MQTT

MQTT (MQ Telemetry Transport) is a messaging protocol qui a été créé pour répondre au besoin d'une méthode simple et légère pour transférer des données vers / depuis des périphériques de faible puissance, tels que ceux utilisés dans les applications industrielles.

Avec la popularité croissante des appareils IoT (Internet of Things), MQTT a connu une utilisation croissante, conduisant à sa normalisation par OASIS et ISO.

Le protocole prend en charge un seul modèle de messagerie, à savoir le modèle Publier-Souscrire: chaque message envoyé par un client contient un «sujet» associé, utilisé par le courtier pour l'acheminer vers les clients abonnés. Les noms de sujets peuvent être des chaînes simples comme «oiltemp» ou une chaîne de type chemin «motor/1/rpm».

Afin de recevoir des messages, un client s'abonne à un ou plusieurs sujets en utilisant son nom exact ou une chaîne contenant l'un des caractères génériques pris en charge («#» pour les sujets à plusieurs niveaux et «+» pour les niveaux uniques »).

3. Configuration du projet

Pour inclure la bibliothèque Paho dans un projet Maven, nous devons ajouter la dépendance suivante:


  org.eclipse.paho
  org.eclipse.paho.client.mqttv3
  1.2.0

La dernière version du module de bibliothèque Java deEclipse Paho peut être téléchargée depuis Maven Central.

4. Configuration du client

Lors de l'utilisation de la bibliothèque Paho, la première chose à faire pour envoyer et / ou recevoir des messages d'un courtier MQTT est deobtain an implementation of the IMqttClient interfaceCette interface contient toutes les méthodes requises par une application afin d'établir une connexion au serveur, envoyer et recevoir des messages.

Paho sort de la boîte avec deux implémentations de cette interface, une asynchrone (MqttAsyncClient) et une synchrone (MqttClient). Dans notre cas, nous allons nous concentrer sur le synchrone version, qui a une sémantique plus simple.

La configuration elle-même est un processus en deux étapes: nous créons d'abord une instance de la classeMqttClient, puis nous la connectons à notre serveur. La sous-section suivante détaille ces étapes.

4.1. Création d'une nouvelle instanceIMqttClient

L'extrait de code suivant montre comment créer une nouvelle instance synchroneIMqttClient:

String publisherId = UUID.randomUUID().toString();
IMqttClient publisher = new MqttClient("tcp://iot.eclipse.org:1883",publisherId);

Dans ce cas,we’re using the simplest constructor available, which takes the endpoint address of our MQTT broker and a client identifier, qui identifie de manière unique notre client.

Dans notre cas, nous avons utilisé un UUID aléatoire, ainsi un nouvel identifiant de client sera généré à chaque exécution.

Paho fournit également des constructeurs supplémentaires que nous pouvons utiliser afin de personnaliser le mécanisme de persistance utilisé pour stocker les messages non acquittés et / ou lesScheduledExecutorService utilisés pour exécuter les tâches d'arrière-plan requises par l'implémentation du moteur de protocole.

The server endpoint we’re using is a public MQTT broker hosted by the Paho project, qui permet à toute personne disposant d'une connexion Internet de tester des clients sans aucune authentification.

4.2. Connexion au serveur

Notre instanceMqttClient nouvellement créée n'est pas connectée au serveur. We do so by calling its connect() method, en passant éventuellement une instanceMqttConnectOptions qui nous permet de personnaliser certains aspects du protocole.

En particulier, nous pouvons utiliser ces options pour transmettre des informations supplémentaires telles que les informations d'identification de sécurité, le mode de récupération de session, le mode de reconnexion, etc.

La classeMqttConnectionOptions expose ces options sous forme de propriétés simples que nous pouvons définir à l'aide des méthodes de définition normales. Nous n'avons besoin que de définir les propriétés requises pour notre scénario. Les propriétés restantes prendront les valeurs par défaut.

Le code utilisé pour établir une connexion au serveur ressemble généralement à ceci:

MqttConnectOptions options = new MqttConnectOptions();
options.setAutomaticReconnect(true);
options.setCleanSession(true);
options.setConnectionTimeout(10);
publisher.connect(options);

Ici, nous définissons nos options de connexion pour que:

  • La bibliothèque essaiera automatiquement de se reconnecter au serveur en cas de défaillance du réseau.

  • Il éliminera les messages non envoyés d'une exécution précédente

  • Le délai de connexion est défini sur 10 secondes.

5. Envoi de messages

L'envoi de messages en utilisant unMqttClient déjà connecté est très simple. We use one of the publish() method variants to send the payload, which is always a byte array, to a given topic, en utilisant l'une des options de qualité de service suivantes:

  • 0 - sémantique «au plus une fois», également appelée «feu et oublie». Utilisez cette option lorsque la perte de message est acceptable, car elle n'exige aucun type d'accusé de réception ni de persistance.

  • 1 - “au moins une fois” sémantique. Utilisez cette option lorsque la perte de message n'est pas acceptableand vos abonnés peuvent gérer les doublons

  • 2 - sémantique «exactement une fois». Utilisez cette option lorsque la perte de message n'est pas acceptableand vos abonnés ne peuvent pas gérer les doublons

Dans notre exemple de projet, la classeEngineTemperatureSensor  joue le rôle d'un capteur fictif qui produit une nouvelle lecture de température à chaque fois que nous invoquons sa méthodecall().

Cette classe implémente l'interfaceCallable afin que nous puissions l'utiliser facilement avec l'une des implémentationsExecutorService disponibles dans le packagejava.util.concurrent:

public class EngineTemperatureSensor implements Callable {

    // ... private members omitted

    public EngineTemperatureSensor(IMqttClient client) {
        this.client = client;
    }

    @Override
    public Void call() throws Exception {
        if ( !client.isConnected()) {
            return null;
        }
        MqttMessage msg = readEngineTemp();
        msg.setQos(0);
        msg.setRetained(true);
        client.publish(TOPIC,msg);
        return null;
    }

    private MqttMessage readEngineTemp() {
        double temp =  80 + rnd.nextDouble() * 20.0;
        byte[] payload = String.format("T:%04.2f",temp)
          .getBytes();
        return new MqttMessage(payload);
    }
}

The MqttMessage encapsulates the payload itself, the requested Quality-of-Service and also the retained flag for the message. Cet indicateur indique au courtier qu'il doit conserver ce message jusqu'à ce qu'il soit consommé par un abonné.

Nous pouvons utiliser cette fonctionnalité pour implémenter un comportement de «dernière bonne utilisation connue». Ainsi, lorsqu'un nouvel abonné se connecte au serveur, il reçoit immédiatement le message conservé.

6. Recevoir des messages

Afin de recevoir des messages du courtier MQTT,we need to use one of the subscribe() method variants, qui nous permettent de spécifier:

  • Un ou plusieurs filtres de sujet pour les messages que nous voulons recevoir

  • La QoS associée

  • Le gestionnaire de rappel pour traiter les messages reçus

Dans l'exemple suivant, nous montrons comment ajouter un écouteur de message à une instanceIMqttClient existante pour recevoir des messages d'une rubrique donnée. Nous utilisons unCountDownLatch comme mécanisme de synchronisation entre notre rappel et le thread d'exécution principal, en le décrémentant à chaque fois qu'un nouveau message arrive.

Dans l'exemple de code, nous avons utilisé une autre instanceIMqttClient pour recevoir des messages. Nous l'avons fait simplement pour préciser quel client faisait quoi, mais ce n'est pas une limitation de Paho. Si vous le souhaitez, vous pouvez utiliser le même client pour publier et recevoir des messages:

CountDownLatch receivedSignal = new CountDownLatch(10);
subscriber.subscribe(EngineTemperatureSensor.TOPIC, (topic, msg) -> {
    byte[] payload = msg.getPayload();
    // ... payload handling omitted
    receivedSignal.countDown();
});
receivedSignal.await(1, TimeUnit.MINUTES);

La variantesubscribe() utilisée ci-dessus prend une instanceIMqttMessageListener comme deuxième argument.

Dans notre cas, nous utilisons une simple fonction lambda qui traite la charge utile et décrémente un compteur. Si pas assez de messages arrivent dans la fenêtre de temps spécifiée (1 minute), la méthodeawait() lèvera une exception.

Lorsque vous utilisez Paho, nous n'avons pas besoin d'accuser explicitement la réception du message. Si le rappel est renvoyé normalement, Paho considère que sa consommation a abouti et envoie un accusé de réception au serveur.

Si le rappel renvoie unException, le client sera arrêté. Please note that this will result in loss of any messages sent with QoS level of 0.

Les messages envoyés avec QoS niveau 1 ou 2 seront renvoyés par le serveur une fois que le client est reconnecté et s'abonne à nouveau à la rubrique.

7. Conclusion

Dans cet article, nous avons montré comment nous pouvons ajouter une prise en charge du protocole MQTT dans nos applications Java à l'aide de la bibliothèque fournie par le projet Eclipse Paho.

Cette bibliothèque gère tous les détails de protocole de bas niveau, nous permettant de nous concentrer sur d'autres aspects de notre solution, tout en laissant un espace suffisant pour personnaliser des aspects importants de ses fonctionnalités internes, telles que la persistance des messages.

Le code présenté dans cet article est disponibleover on GitHub.