Клиент MQTT на Java

Клиент MQTT на Java

1. обзор

В этом руководстве мы увидим, как добавить обмен сообщениями MQTT в проект Java, используя библиотеки, предоставляемыеEclipse Paho project.

2. MQTT Primer

MQTT (MQ Telemetry Transport) is a messaging protocol, который был создан для удовлетворения потребности в простом и легком методе передачи данных на / с устройств с низким энергопотреблением, например, используемых в промышленных приложениях.

С ростом популярности устройств IoT (Internet of Things), MQTT стал более широко использоваться, что привело к его стандартизации с помощью OASIS и ISO.

Протокол поддерживает единый шаблон обмена сообщениями, а именно шаблон публикации-подписки: каждое сообщение, отправляемое клиентом, содержит связанную «тему», которая используется посредником для направления его подписанным клиентам. Имена тем могут быть простыми строками, такими как «oiltemp» или строкой типа пути «motor/1/rpm».

Чтобы получать сообщения, клиент подписывается на одну или несколько тем, используя свое точное имя или строку, содержащую один из поддерживаемых подстановочных знаков («#» для многоуровневых тем и «+» для одноуровневых »).

3. Настройка проекта

Чтобы включить библиотеку Paho в проект Maven, мы должны добавить следующую зависимость:


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

Последнюю версию модуля библиотеки JavaEclipse Paho можно загрузить с Maven Central.

4. Настройка клиента

При использовании библиотеки Paho первое, что нам нужно сделать для отправки и / или получения сообщений от брокера MQTT, - этоobtain an implementation of the IMqttClient interface. Этот интерфейс содержит все методы, необходимые приложению для установки подключение к серверу, отправка и получение сообщений.

Paho поставляется с двумя реализациями этого интерфейса: асинхронной (MqttAsyncClient) и синхронной (MqttClient).  В нашем случае мы сосредоточимся на синхронной версия, имеющая более простую семантику.

Сама настройка представляет собой двухэтапный процесс: сначала мы создаем экземпляр классаMqttClient, а затем подключаем его к нашему серверу. В следующем подразделе подробно описаны эти шаги.

4.1. Создание нового экземпляраIMqttClient

В следующем фрагменте кода показано, как создать новый синхронный экземплярIMqttClient:

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

В данном случаеwe’re using the simplest constructor available, which takes the endpoint address of our MQTT broker and a client identifier, который однозначно идентифицирует нашего клиента.

В нашем случае мы использовали случайный UUID, поэтому новый идентификатор клиента будет генерироваться при каждом запуске.

Paho также предоставляет дополнительные конструкторы, которые мы можем использовать для настройки механизма сохраняемости, используемого для хранения неподтвержденных сообщений и / илиScheduledExecutorService, используемых для выполнения фоновых задач, необходимых для реализации механизма протокола.

The server endpoint we’re using is a public MQTT broker hosted by the Paho project, который позволяет любому, у кого есть подключение к Интернету, тестировать клиентов без необходимости какой-либо аутентификации.

4.2. Подключение к серверу

Наш недавно созданный экземплярMqttClient не подключен к серверу. We do so by calling its connect() method, опционально передавая синстанциюMqttConnectOptions , которая позволяет нам настраивать некоторые аспекты протокола.

В частности, мы можем использовать эти параметры для передачи дополнительной информации, такой как учетные данные безопасности, режим восстановления сеанса, режим переподключения и так далее.

КлассMqttConnectionOptions предоставляет эти параметры как простые свойства, которые мы можем установить с помощью обычных методов установки. Нам нужно только установить свойства, необходимые для нашего сценария - остальные будут принимать значения по умолчанию.

Код, используемый для установления соединения с сервером, обычно выглядит следующим образом:

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

Здесь мы определяем наши параметры подключения так, чтобы:

  • Библиотека автоматически попытается переподключиться к серверу в случае сбоя сети

  • Он будет отбрасывать неотправленные сообщения от предыдущего запуска

  • Тайм-аут соединения установлен на 10 секунд

5. Отправка сообщений

Отправка сообщений с использованием уже подключенногоMqttClient очень проста. We use one of the publish() method variants to send the payload, which is always a byte array, to a given topic, используя один из следующих вариантов качества обслуживания:

  • 0 - семантика «не более одного раза», также известная как «запустить и забыть». Используйте эту опцию, когда потеря сообщения приемлема, так как она не требует какого-либо подтверждения или сохранения

  • 1 - семантика «хотя бы один раз». Используйте эту опцию, если потеря сообщения недопустимаand, ваши подписчики могут обрабатывать дубликаты

  • 2 - семантика «ровно один раз». Используйте эту опцию, когда потеря сообщения недопустимаand ваши подписчики не могут обрабатывать дубликаты

В нашем примере проекта классEngineTemperatureSensor играет роль фиктивного датчика, который выдает новое значение температуры каждый раз, когда мы вызываем его методcall().

Этот класс реализует интерфейсCallable, поэтому мы можем легко использовать его с одной из реализацийExecutorService, доступных в пакетеjava.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. Этот флаг указывает брокеру, что он должен сохранить это сообщение до тех пор, пока оно не будет использовано подписчиком.

Мы можем использовать эту функцию для реализации «последнего известного исправного» поведения, поэтому, когда новый подписчик подключается к серверу, он сразу же получает сохраненное сообщение.

6. Получение сообщений

Чтобы получать сообщения от брокера MQTT,we need to use one of the subscribe() method variants, которые позволяют нам указать:

  • Один или несколько тематических фильтров для сообщений, которые мы хотим получать

  • Связанное QoS

  • Обработчик обратного вызова для обработки полученных сообщений

В следующем примере мы показываем, как добавить слушателя сообщений к существующему экземпляруIMqttClient для получения сообщений из заданной темы. Мы используемCountDownLatch в качестве механизма синхронизации между нашим обратным вызовом и основным потоком выполнения, уменьшая его каждый раз, когда приходит новое сообщение.

В примере кода мы использовали другой экземплярIMqttClient для получения сообщений. Мы сделали это просто, чтобы уточнить, какой клиент делает что, но это не ограничение Paho - если вы хотите, вы можете использовать тот же клиент для публикации и получения сообщений:

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);

Используемый выше вариантsubscribe() принимает экземплярIMqttMessageListener в качестве второго аргумента.

В нашем случае мы используем простую лямбда-функцию, которая обрабатывает полезную нагрузку и уменьшает счетчик. Если в указанное временное окно (1 минута) поступит недостаточно сообщений, методawait() вызовет исключение.

При использовании Paho нам не нужно явно подтверждать получение сообщения. Если обратный вызов возвращается нормально, Paho предполагает его успешное использование и отправляет подтверждение на сервер.

Если обратный вызов выдаетException, клиент будет отключен. Please note that this will result in loss of any messages sent with QoS level of 0.

Сообщения, отправленные с уровнем QoS 1 или 2, будут повторно отправлены сервером после повторного подключения клиента и повторной подписки на тему.

7. Заключение

В этой статье мы продемонстрировали, как мы можем добавить поддержку протокола MQTT в наши приложения Java, используя библиотеку, предоставленную проектом Eclipse Paho.

Эта библиотека обрабатывает все подробности протокола низкого уровня, что позволяет нам сосредоточиться на других аспектах нашего решения, оставляя при этом достаточно места для настройки важных аспектов его внутренних функций, таких как сохранение сообщений.

Код, показанный в этой статье, доступенover on GitHub.