Подключение к брокеру MQTT с помощью Websocket

В последние годы, с быстрым развитием Web front-end, постоянно появляются новые возможности браузеров, все больше и больше приложений могут быть реализованы на стороне браузера через механизм рендеринга браузера. Также широко используется WebSocket, метод мгновенной связи для веб-приложений.

WebSocket — это протокол компьютерной связи, обеспечивающий полнодуплексные каналы связи через одно TCP-соединение. Протокол WebSocket был стандартизирован IETF как RFC 6455 в 2011 году, а API WebSocket в Web IDL в настоящее время стандартизируется W3C. 1

Глава 6 протокола MQTT определяет условия, которым должен удовлетворять MQTT для передачи через соединение WebSocket [RFC6455], и здесь подробно не рассматривается.

Сравнение двух клиентов

Paho.mqtt.js

Paho — это проект MQTT-клиента от Eclipse, а JavaScript-клиент Paho является одной из браузерных библиотек, использующих WebSockets для соединения с MQTT-сервером. По сравнению с другой библиотекой соединений JavaScript, она имеет меньше возможностей и не рекомендуется.

MQTT.js

MQTT.js — это полностью открытая клиентская библиотека для протокола MQTT, написанная на JavaScript и доступная для Node.js и браузеров. На стороне Node.js она может быть установлена через глобальную установку и подключена через командную строку. Также он поддерживает соединения MQTT/TCP, MQTT/TLS, MQTT/WebSocket. Стоит отметить, что MQTT.js также имеет хорошую поддержку для WeChat Mini Program.

В этой статье мы будем использовать библиотеку MQTT.js для объяснения WebSocket-соединений.

Установите MQTT.js

Если на вашей машине установлена среда выполнения Node.js, вы можете установить MQTT.js напрямую с помощью команды npm.

Установка в текущий каталог

npm install mqtt --save
Вход в полноэкранный режим Выйти из полноэкранного режима

Ссылки на CDN

Или используйте адреса CDN напрямую без установки

<script src="https://unpkg.com/mqtt/dist/mqtt.min.js"></script>

<script>
    // Globally initializes an mqtt variable
    console.log(mqtt)
</script>
Войти в полноэкранный режим Выйти из полноэкранного режима

Подключение к MQTT-брокеру

В этой статье будет использоваться бесплатный публичный MQTT-брокер, предоставляемый компанией EMQX. Этот сервис был создан на основе облачной платформы EMQX MQTT IoT. Ниже приведена информация о доступе к брокеру:

  • Брокер: broker.emqx.io
  • TCP-порт: 1883
  • Порт Websocket: 8083

EMQX использует порт 8083 для обычных соединений и 8084 для WebSocket по TLS.

Для простоты давайте поместим подписчика и издателя в один файл.

const clientId = 'mqttjs_' + Math.random().toString(16).substr(2, 8)

const host = 'ws://broker.emqx.io:8083/mqtt'

const options = {
  keepalive: 60,
  clientId: clientId,
  protocolId: 'MQTT',
  protocolVersion: 4,
  clean: true,
  reconnectPeriod: 1000,
  connectTimeout: 30 * 1000,
  will: {
    topic: 'WillMsg',
    payload: 'Connection Closed abnormally..!',
    qos: 0,
    retain: false
  },
}

console.log('Connecting mqtt client')
const client = mqtt.connect(host, options)

client.on('error', (err) => {
  console.log('Connection error: ', err)
  client.end()
})

client.on('reconnect', () => {
  console.log('Reconnecting...')
})
Вход в полноэкранный режим Выход из полноэкранного режима

Адрес соединения

Адрес соединения, продемонстрированный выше, может быть разделен на: ws: // broker . emqx.io : 8083 /mqtt.

Это protocol // имя хоста . domain : port / path.

Новички, скорее всего, допустят следующие ошибки.

  • В адресе соединения не указан протокол: WebSocket — это протокол связи, который использует ws (незашифрованный), wss (зашифрованный SSL) в качестве идентификатора протокола. Клиент MQTT.js поддерживает несколько протоколов, и адрес соединения должен указывать тип протокола.
  • Адрес соединения не указывает порт: MQTT не указывает порт для доступа по протоколу WebSocket, а EMQX использует 8083 и 8084 в качестве портов по умолчанию для незашифрованных и зашифрованных соединений соответственно. Порт по умолчанию протокола WebSocket такой же, как и HTTP (80/443), отсутствие порта означает, что WebSocket использует порт по умолчанию для соединения. С другой стороны, нет необходимости указывать порт при использовании стандартного MQTT-соединения. Например, MQTT.js может использовать mqtt://localhost на стороне Node.js для подключения к стандартному порту MQTT 1883, а когда адрес подключения mqtts://localhost, он будет подключен к порту 8884.
  • Адрес подключения без пути: MQTT-WebSoket единообразно использует /path в качестве пути соединения, который должен быть указан при подключении, а путь, используемый на EMQX, — /mqtt.
  • Протокол не соответствует порту: используйте соединение wss, но подключайтесь к порту 8083.
  • Использование незашифрованных соединений WebSocket под HTTPS: такие организации, как Google, продвигают HTTPS и одновременно ограничивают безопасность через ограничения браузера, т.е. использование незашифрованного протокола ws для инициирования запросов на соединение автоматически запрещается браузером под HTTPS-соединениями.
  • Сертификат не соответствует адресу соединения: длинный, см. ниже для подробностей Включение SSL/TLS для EMQX.

Параметры подключения

В приведенном выше коде options — это опции клиентского соединения. Ниже приведено описание основных параметров, остальные параметры смотрите на https://github.com/mqttjs/MQTT.js#client.

  • keepalive: время сердцебиения, по умолчанию 60 секунд, установите 0, чтобы отключить.
  • clientId: идентификатор клиента, который по умолчанию генерируется случайным образом'mqttjs_' + Math.random().toString(16).substr(2, 8).
  • имя пользователя: имя пользователя соединения (необязательно)
  • пароль: пароль подключения (необязательно)
  • clean: true, установите значение false для получения сообщений QoS 1 и 2 в автономном режиме.
  • reconnectPeriod: по умолчанию 1000 миллисекунд, интервал между переподключениями, дублированием идентификатора клиента, сбоями аутентификации и т.д. Клиент будет подключаться заново.
  • connectTimeout: по умолчанию 30 * 1000 миллисекунд, время ожидания до получения CONNACK, т.е. время ожидания соединения.
  • will: сообщение will, сообщение, которое Брокер будет отправлять автоматически, когда клиент будет серьезно отключен. Общий формат следующий:
    • topic: тема для публикации
    • полезная нагрузка: сообщение, которое будет опубликовано
    • qos: QoS
    • сохранить: сохранить знак

Подписка/отписка

Подписка может быть осуществлена только после успешного подключения, а подписываемые темы должны соответствовать правилам темы подписки MQTT.

Примечание: Асинхронная неблокирующая функция JavaScript обеспечивает успешное соединение только после события connect или с помощью client.connected для определения успешности соединения.

client.on('connect', () => {
  console.log('Client connected:' + clientId)
  // Subscribe
  client.subscribe('testtopic', { qos: 0 })
})
Вход в полноэкранный режим Выход из полноэкранного режима
// Unsubscribe
client.unubscribe('testtopic', () => {
  console.log('Unsubscribed')
})
Вход в полноэкранный режим Выход из полноэкранного режима

Публикация/получение сообщений

Публикация сообщений в определенные темы. Публикуемая тема должна соответствовать правилу MQTT publish topic. В противном случае она будет отключена. Нет необходимости подписываться на эту тему перед публикацией, но необходимо убедиться, что клиент уже успешно подключился.

// Publish
client.publish('testtopic', 'ws connection demo...!', { qos: 0, retain: false })
Вход в полноэкранный режим Выход из полноэкранного режима
// Received
client.on('message', (topic, message, packet) => {
  console.log('Received Message: ' + message.toString() + 'nOn topic: ' + topic)
})
Войти в полноэкранный режим Выход из полноэкранного режима

Мини-программа WeChat

Библиотека MQTT.js использует идентификатор протокола wxs для специальной обработки WeChat Mini Program. Примечание: Спецификация разработки апплета требует использования зашифрованного соединения, а адрес соединения должен быть похож на wxs://broker.emqx.io:8084/mqtt.

Включите SSL/TLS для EMQX

EMQ встроенный самоподписанный сертификат, зашифрованное WebSocket соединение было запущено по умолчанию, но большинство браузеров будут сообщать об ошибках недействительного сертификата, таких как net::ERR_CERT_COMMON_NAME_INVALID (Chrome, 360 и другие браузеры на ядре WebKit в режиме разработчика. Вкладка Console может быть использована для просмотра большинства ошибок подключения). Причина этой ошибки заключается в том, что браузер не может проверить действительность самоподписанного сертификата. Читателю необходимо приобрести доверенный сертификат в центре сертификации и обратиться к соответствующему разделу этой статьи для действий по настройке: Включить SSL/TLS для брокера EMQX MQTT.

Здесь кратко описаны условия, необходимые для включения сертификатов SSL/TLS:

  • Привязать доменное имя к публичному адресу MQTT-брокера: сертификат, выданный центром сертификации, подписывается для доменного имени.
  • Подать заявку на сертификат: подать заявку на сертификат для доменного имени, используемого с центром сертификации, обращая внимание на то, чтобы выбрать надежный центр сертификации и чтобы сертификат различал общее доменное имя и имя хоста.
  • Выберите протокол wss при использовании зашифрованного соединения и используйте доменное имя для подключения: после связывания доменного имени — сертификации, необходимо использовать доменное имя для подключения вместо IP-адреса, чтобы браузер проверил сертификацию по доменному имени для установления соединения после прохождения проверки.

Конфигурация EMQX

Откройте конфигурационный файл etc/emqx.conf и измените следующие настройки:

# wss listening address
listener.wss.external = 8084

# Modify key file address
listener.wss.external.keyfile = etc/certs/cert.key

# Modify certificate file address
listener.wss.external.certfile = etc/certs/cert.pem
Войти в полноэкранный режим Выйти из полноэкранного режима

После завершения перезапустите EMQX.

Вы можете использовать свои файлы сертификатов и ключей, чтобы заменить их непосредственно в каталоге etc/certs/.

Настройка обратных прокси и сертификатов на Nginx

Использование Nginx для обратного проксирования и шифрования WebSocket позволяет снизить вычислительную нагрузку на брокер EMQX и одновременно реализовать мультиплексирование доменных имен. Балансировка нагрузки Nginx также позволяет распределить несколько внутренних служб.

# It is recommended that WebSocket also bind to port 443.
listen 443, 8084;
server_name example.com;

ssl on;

ssl_certificate /etc/cert.crt;  # certificate path
ssl_certificate_key /etc/cert.key; # key path


# upstream server list
upstream emq_server {
    server 10.10.1.1:8883 weight=1;
    server 10.10.1.2:8883 weight=1;
    server 10.10.1.3:8883 weight=1;
}

# Common website application
location / {
    root www;
    index index.html;
}

# Reverse proxy to EMQX unencrypted WebSocket
location / {
    proxy_redirect off;
    # upstream
    proxy_pass http://emq_server;

    proxy_set_header Host $host;
    # Reverse proxy retains client address
    proxy_set_header X-Real_IP $remote_addr;
    proxy_set_header X-Forwarded-For $remote_addr:$remote_port;
    # WebSocket extra request header
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection “upgrade”;
}
Вход в полноэкранный режим Выход из полноэкранного режима

Другие ресурсы

Полный код проекта: https://github.com/emqx/MQTT-Client-Examples/tree/master/mqtt-client-WebSocket

Онлайновый инструментарий MQTT WebSocket: https://www.emqx.com/en/mqtt/mqtt-websocket-toolkit


  1. https://en.wikipedia.org/wiki/WebSocket

Оцените статью
devanswers.ru
Добавить комментарий