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

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

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


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


Paho.mqtt.js

Транслировать — это проект клиента MQTT от Eclipse, а клиент Paho JavaScript — это одна из библиотек на основе браузера, которая использует WebSockets для подключения к серверу MQTT. По сравнению с другой библиотекой подключения JavaScript, она имеет меньше функций и не рекомендуется.


MQTT.js

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

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


Установите 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. Информация о доступе к брокеру следующая:

  • Маклер: Broker.emqx.io
  • TCP-порт: 1883 г.
  • Порт веб-сокета: 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 // host name . 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#клиент.

  • 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 message, сообщение, которое Брокер отправит автоматически, когда клиент резко отключится. Общий формат:
    • тема: тема для публикации
    • полезная нагрузка: сообщение, которое будет опубликовано
    • качество обслуживания: качество обслуживания
    • сохранить: сохранить знак


Подписаться/отписаться

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

Примечание. JavaScript Асинхронная неблокирующая функция JavaScript обеспечивает успешное соединение только после события соединения или с помощью 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
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. Примечание. Спецификация разработки апплета требует использования зашифрованного соединения, а адрес соединения должен быть аналогичен wxs://broker.emqx.io:8084/mqtt.


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

Встроенный самозаверяющий сертификат EMQ, зашифрованное соединение WebSocket запущено по умолчанию, но большинство браузеров сообщают о недопустимых ошибках сертификата, таких как net::ERR_CERT_COMMON_NAME_INVALID (Chrome, 360 и другие браузеры с ядром WebKit в режиме разработчика. Вкладку «Консоль» можно использовать для просмотра большинства ошибок подключения). Причина этой ошибки в том, что браузер не может проверить действительность самоподписанного сертификата. Читателю необходимо приобрести доверенный сертификат в центре сертификации и обратиться к соответствующему разделу этой статьи для действий по настройке: Включить 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”;
}
Войти в полноэкранный режим

Выйти из полноэкранного режима


Другие источники

Полный код проекта:

Онлайн-инструментарий MQTT WebSocket:


  1. https://en.wikipedia.org/wiki/Веб-сокет