Como as máquinas se comunicam - protocolo MQTT


Em um artigo anterior, vimos o protocolo Modbus , que é o padrão de fato do setor para interação M2M . Desenvolvido em 1979, possui várias desvantagens significativas que o MQTT resolve.

O protocolo MQTT é bastante jovem (padronizado apenas em 2016), mas já conseguiu ser amplamente utilizado na indústria e na IoT. Foi especialmente projetado para ser o mais compacto possível, para canais instáveis ​​da Internet e dispositivos de baixa energia, e permite a entrega garantida de mensagens em caso de perda e desconexão de pacotes.

Principais recursos do protocolo MQTT:

  • Compacto e leve - transferência mínima de dados para economizar tráfego.
  • Resistência a perdas - entrega garantida nas condições de conexões de rede instáveis.
  • Assíncrono - permite atender a um grande número de dispositivos e não depende de atrasos na rede.
  • Suporte a QoS - a capacidade de controlar a prioridade da mensagem e garantir a entrega da mensagem ao destinatário.
  • Configuração dinâmica - não requer coordenação prévia de campos e formatos de dados, pode ser configurada em tempo real.
  • Funciona para NAT - os clientes podem estar atrás do NAT, apenas o servidor (broker) deve ter um IP real. Permite que você faça sem VPN e encaminhamento de porta.
  • Endereçamento conveniente - os campos de dados têm nomes de texto compreensíveis para os seres humanos. Não há necessidade de lembrar endereços digitais e compensações de bits.

No artigo, compararemos o MQTT e o Modbus, analisaremos a estrutura do protocolo, os conceitos básicos e tentaremos usar o broker MQTT na nuvem como exemplo em uma conexão à Internet instável.

Histórico do Protocolo MQTT


O MQTT foi desenvolvido pela IBM em 1999 e foi inicialmente usado internamente para suas soluções.

Em novembro de 2011, a IBM e a Eurotech anunciaram sua participação no grupo de trabalho Eclipse M2M e a transferência do código MQTT para o projeto Eclipse Paho.

Em 2013, o consórcio OASIS (Organização para o Avanço de Padrões Estruturados de Informações) iniciou o processo de padronização do protocolo MQTT. Até esse momento, a especificação do protocolo foi publicada sob uma licença gratuita e empresas como a Eurotech (anteriormente conhecida como Arcom) já usam o protocolo em seus produtos.

Em outubro de 2014, o OASIS publicou o primeiro padrão oficial do protocolo MQTT.

Em 2016, o protocolo foi padronizado pela Organização Internacional de Normalização ISO e recebeu o número ISO / IEC 20922.

Desde 2014, o interesse no protocolo começa a crescer rapidamente e, a julgar pela programação do Google Trends, hoje excede o interesse no Modbus.


Referência do Google Trends

Conceitos básicos


O MQTT possui uma arquitetura cliente-servidor. As mensagens ocorrem através de um servidor central chamado corretor. Sob condições normais, os clientes não podem se comunicar diretamente entre si e todas as trocas de dados ocorrem por meio de um broker.

Os clientes podem atuar como provedores de dados (Publicador) e como destinatários de dados (Assinante). Em uma tradução para o russo, esses termos geralmente são traduzidos como editor e assinante, mas, para evitar confusão, usaremos apenas a terminologia original.


No protocolo MQTT, os clientes se comunicam por meio de um nó central

No nível do aplicativo, o protocolo é executado sobre TCP / IP e pode conectar facilmente objetos remotos diretamente pela Internet, sem a necessidade de túneis VPN. Basta que o broker tenha um endereço IP real e todos os clientes possam se conectar a ele. Nesse caso, os clientes podem estar localizados atrás do NAT. Como os clientes iniciam a conexão no protocolo MQTT, o encaminhamento de porta não é necessário para estabelecer uma conexão, enquanto no Modbus / TCP o servidor inicia uma conexão (principal), que requer acessibilidade direta à rede.

A porta do broker MQTT padrão para conexões TCP de entrada é 1883 . Ao usar uma conexão SSL segura, a porta 8883 é usada .

Corretor


Um broker é o hub central do MQTT para interação com o cliente. A troca de dados entre clientes ocorre apenas através de um broker. O broker pode ser um software de servidor ou um controlador. Suas tarefas incluem receber dados de clientes, processar e armazenar dados, entregar dados a clientes e monitorar a entrega de mensagens.

Editor / Assinante


Para entender a diferença entre Publisher e Subscriber, vamos dar um exemplo simples: um sensor de umidade mede a umidade em uma sala e, se cair abaixo de um determinado nível, o umidificador é ativado.

Nesse caso, o sensor de umidade atua como um Publicador : sua tarefa é apenas publicar dados no broker. O umidificador atua como um Assinante : ele assina atualizações de dados de umidade e recebe dados atualizados do broker, enquanto o umidificador pode decidir em que ponto ativar a umidificação.

Nesse esquema, os clientes MQTT, ou seja, o sensor e o umidificador, não estão cientes da existência um do outro e não interagem diretamente. O broker pode receber dados de várias fontes, manipulá-las, por exemplo, calcular o valor médio de vários sensores e retornar os dados processados ​​ao assinante.


O Publisher envia dados para o corretor, o Assinante assina atualizações desses dados

Ao mesmo tempo, a assincronia do protocolo MQTT prevê que o sensor e o umidificador possam estar online em momentos diferentes, perder pacotes e ficar inacessíveis. O intermediário cuidará de armazenar os últimos dados recebidos do sensor na memória e garantirá sua entrega ao umidificador.

Tópico


O MQTT usa tópicos para identificar entidades, na tradução para o russo também são chamados de canais. Os tópicos consistem em caracteres UTF8 e têm uma estrutura em árvore semelhante a um sistema de arquivos UNIX. Esse é um mecanismo conveniente para nomear entidades em uma forma legível por humanos.

Um exemplo de tópicos no MQTT

#     home/kitchen/temperature #     home/sleeping-room/temperature #     home/outdoor/light 

Essa abordagem permite que você veja visualmente quais dados são transmitidos, e é conveniente desenvolver e depurar o código sem precisar memorizar o endereço digital da localização dos dados, como é feito no Modbus.

Os tópicos também incluem sintaxe curinga, familiar para aqueles que trabalharam com o sistema de arquivos UNIX. O curinga pode ser de nível único e multinível.

Um curinga de nível único é indicado por um + .

Por exemplo, para receber dados de sensores de temperatura em todas as salas da casa, o assinante precisa se inscrever em um tópico:

 home/+/temperature 

Como resultado, ele se inscreverá para receber dados de tais sensores:

 home/kitchen/temperature home/sleeping-room/temperature home/living-room/temperature home/outdoor/temperature 

Um curinga de vários níveis é indicado pelo símbolo " # ".
Um exemplo de obtenção de dados de todos os sensores em todos os cômodos da casa:

 home/# 

A inscrição nesse tópico permitirá que você receba dados de tais sensores:

 home/kitchen/temperature home/kitchen/humidity home/kitchen/light home/sleeping-room/temperature home/sleeping-room/humidity home/sleeping-room/light .... 

Identificação do cliente


Para controle de acesso, o MQTT fornece autenticação de cliente, ao contrário do protocolo Modbus, que não possui essa função. Os seguintes campos são usados ​​para controle de acesso:

ClientId - identificador exclusivo (campo obrigatório) do cliente. Deve ser exclusivo para cada cliente. A versão atual do padrão MQTT 3.1.1 permite usar o campo ClientId vazio se você não precisar salvar o status da conexão.

Nome de usuário - (campo opcional) login para autenticação, no formato UTF-8. Pode não ser único. Por exemplo, um grupo de clientes pode efetuar login com o mesmo nome de usuário / senha.

Senha - (campo opcional) pode ser enviada apenas junto com o campo Nome do usuário, enquanto o Nome do usuário pode ser transmitido sem o campo Senha. 65535 bytes no máximo. É importante saber que o nome e a senha são transmitidos de forma clara. Portanto, se os dados são transmitidos por redes públicas, você deve usar o SSL para criptografar a conexão.

Estrutura do pacote


Como mencionado acima, no protocolo MQTT, os clientes sempre iniciam uma conexão, independentemente de serem destinatários (Assinante) ou fornecedores (Publicador) de dados. Analisaremos o pacote com a conexão que foi interceptada usando o programa Wireshark.


Pacote MQTT transmitido por um canal não criptografado

O cabeçalho TCP mostra que o pacote foi enviado na porta 1883, ou seja, a criptografia não é usada, o que significa que todos os dados estão disponíveis em formato claro, incluindo login e senha.

Manchete


O tipo de mensagem é Connect (comando 0x0001), estabelecendo uma conexão com o broker. Equipes principais: conectar, desconectar, publicar, inscrever-se, cancelar inscrição. Também existem comandos de reconhecimento, manter vivos, etc.

Sinalizador DUP - significa que a mensagem é retransmitida, é usada apenas nos tipos de mensagem PUBLISH, SUBSCRIBE, UNSUBSCRIBE, PUBREL, nos casos em que o broker não recebeu confirmação de recebimento da mensagem anterior.
Nível de QoS - sinalizador de Qualidade de serviço. Discutiremos esse tópico com mais detalhes posteriormente.
Reter - dados publicados com o sinalizador de retenção são armazenados no broker. Após a assinatura subsequente deste tópico, o broker enviará imediatamente uma mensagem com esse sinalizador. Usado apenas em mensagens do tipo Publicar.

Uso prático




Agora, tendo nos familiarizado com a teoria, vamos tentar trabalhar com o MQTT na prática. Para isso, usaremos o programa Mosquitto aberto, que pode funcionar tanto no modo cliente quanto no modo servidor (broker). Funciona no Windows, macOS, Linux. O programa é muito conveniente para depurar e estudar o protocolo MQTT, enquanto também é amplamente utilizado em operações industriais. Nós o usaremos como um cliente para enviar e receber dados de um broker de nuvem remota.

Muitos provedores de nuvem fornecem serviços de broker MQTT, como Microsoft Azure IoT Hub , Amazon AWS IoT e outros. Neste exemplo, usaremos o serviço Cloudmqtt.com, pois ele tem o registro mais simples e uma tarifa gratuita é suficiente para o treinamento.

Após o registro, os detalhes para conectar-se a um corretor estão disponíveis em sua conta. Como nos conectamos ao servidor por meio de redes públicas da Internet, é razoável usar uma porta SSL para criptografar o tráfego.


Detalhes de acesso do broker MQTT na conta pessoal do provedor de nuvem

A flexibilidade do protocolo MQTT permite ao cliente transferir dados não definidos anteriormente no broker. Ou seja, não há necessidade de pré-criar os tópicos necessários nos quais o Publisher pode gravar dados. Usando os dados recebidos da sua conta pessoal, tentaremos redigir manualmente uma solicitação de publicação de dados no tópico habr / test / random e ler a partir dele.

mosquitto_sub - utilitário do cliente do assinante
mosquitto_pub - utilitário cliente do editor

Primeiro, conecte-se ao broker como um assinante e assine para receber dados do tópico
habr / teste / aleatório .

 mosquitto_sub -d --capath /etc/ssl/certs/ --url mqtts://hwjspxxt:7oYugN7Fa5Aa@postman.cloudmqtt.com:27529/habr/test/random Client mosq/zEPZz0glUiR4aEipZA sending CONNECT Client mosq/zEPZz0glUiR4aEipZA received CONNACK (0) Client mosq/zEPZz0glUiR4aEipZA sending SUBSCRIBE (Mid: 1, Topic: habr/test/random, QoS: 0, Options: 0x00) Client mosq/zEPZz0glUiR4aEipZA received SUBACK 

Pode-se ver que a conexão foi bem-sucedida e assinamos o tópico habr / test / random , e agora estamos aguardando dados neste tópico do broker.
Como uma conexão SSL é usada, para verificar o certificado, você deve especificar o caminho pelo qual o programa procurará por certificados de criptografia raiz. Como o serviço em nosso exemplo usa um certificado emitido por uma autoridade de certificação confiável, indicamos o caminho para o armazenamento do sistema para certificados raiz: --capath / etc / ssl / certs /

No caso de um certificado autoassinado, você deve especificar o caminho para a CA desejada. Também é importante considerar a diferença no formato URI para conexões SSL - mqtt s : // e conexões não criptografadas - mqtt: //. No caso de um erro de verificação do certificado, o programa termina sem uma mensagem de erro. Para uma saída mais detalhada, você pode usar a opção --debug
Agora vamos tentar publicar os dados no tópico sem interromper o primeiro programa.

 mosquitto_pub -d --capath /etc/ssl/certs/ --url mqtt://hwjspxxt:7oYugN7Fa5Aa@postman.cloudmqtt.com:27529/habr/test/random -m " !" Client mosq/sWjh9gf8DRASrRZjk6 sending CONNECT Client mosq/sWjh9gf8DRASrRZjk6 received CONNACK (0) Client mosq/sWjh9gf8DRASrRZjk6 sending PUBLISH (d0, q0, r0, m1, 'habr/test/random', ... (22 bytes)) Client mosq/sWjh9gf8DRASrRZjk6 sending DISCONNECT 

Pode-se observar que os dados foram recebidos com sucesso pelo servidor e publicados no tópico desejado. Ao mesmo tempo, na primeira janela em que o programa mosquitto_sub está em execução, vemos como a mensagem foi recebida, até mesmo o Unicode está funcionando, a mensagem está em russo.

 Client mosq/zEPZz0glUiR4aEipZA received PUBLISH (d0, q0, r0, m0, 'habr/test/random', ... (22 bytes))  ! 

QoS e garantia de entrega


No entanto, enviar uma mensagem em tempo real não surpreenderá ninguém, porque o mesmo pode ser feito mesmo com o utilitário banal nc . Portanto, tentaremos simular uma conexão instável entre o assinante e o remetente. Imagine que ambos os clientes trabalhem com GPRS, com uma enorme perda de pacotes e até uma conexão TCP bem-sucedida seja rara, e você precisa garantir que o assinante tenha a garantia de receber uma mensagem de remetente. Nesse caso, as opções de QoS são úteis.

Por padrão, o sinalizador QoS é definido como 0 para mensagens, o que significa "Disparar e esquecer": o Publisher publica a mensagem no broker, mas não exige que a mensagem seja garantida para ser entregue ao assinante. Isso é adequado para dados cuja perda não é crítica, por exemplo, para medições regulares de umidade ou temperatura.

QoS 1: Pelo menos uma vez - pelo menos uma . Esse sinalizador significa que, até que o Publicador receba confirmação de entrega ao assinante, essa publicação será enviada ao corretor e depois ao assinante. Assim, o assinante deve receber esta mensagem pelo menos uma vez.

QoS 2: Exatamente uma vez - um garantido . O sinalizador QoS, que oferece a maior garantia de entrega de mensagens através do uso de procedimentos adicionais para confirmação e conclusão da publicação (PUBREC, PUBREL, PUBCOMP). Aplicável a situações em que é necessário excluir qualquer perda e duplicação de dados dos sensores. Por exemplo, quando um alarme é acionado a partir de uma mensagem recebida, é feita uma chamada de emergência.

Para simular uma comunicação ruim, desligue os dois clientes e tente enviar uma mensagem com a maior prioridade de QoS e também adicione a opção Reter para que a mensagem enviada seja salva no broker.

 mosquitto_pub --retain --qos 2 -d --capath /etc/ssl/certs/ --url mqtt://hwjspxxt:7oYugN7Fa5Aa@postman.cloudmqtt.com:27529/habr/test/random -m "  !" Client mosq/Xwhua3GAyyY9mMd05V sending CONNECT Client mosq/Xwhua3GAyyY9mMd05V received CONNACK (0) Client mosq/Xwhua3GAyyY9mMd05V sending PUBLISH (d0, q2, r1, m1, 'habr/test/random', ... (37 bytes)) Client mosq/Xwhua3GAyyY9mMd05V received PUBREC (Mid: 1) Client mosq/Xwhua3GAyyY9mMd05V sending PUBREL (m1) Client mosq/Xwhua3GAyyY9mMd05V received PUBCOMP (Mid: 1, RC:0) Client mosq/Xwhua3GAyyY9mMd05V sending DISCONNECT 

Agora, depois de algum tempo, nosso destinatário finalmente conseguiu estabelecer uma conexão com a Internet e conectada ao broker:

 mosquitto_sub -d --capath /etc/ssl/certs/ -d --url mqtts://hwjspxxt:7oYugN7Fa5Aa@postman.cloudmqtt.com:27529/habr/test/random Client mosq/VAzcLVMB1MiWhYxoJS sending CONNECT Client mosq/VAzcLVMB1MiWhYxoJS received CONNACK (0) Client mosq/VAzcLVMB1MiWhYxoJS sending SUBSCRIBE (Mid: 1, Topic: habr/test/random, QoS: 0, Options: 0x00) Client mosq/VAzcLVMB1MiWhYxoJS received SUBACK Subscribed (mid: 1): 0 Client mosq/r6UwPnDvx8aNInpPF6 received PUBLISH (d0, q0, r1, m0, 'habr/test/random', ... (37 bytes))   ! 

Conclusão


O MQTT é um protocolo moderno e avançado, desprovido de muitos dos inconvenientes de seus antecessores. Sua flexibilidade permite adicionar dispositivos clientes sem configurar um broker, o que economiza tempo significativamente. O limiar de entrada para entender e configurar o protocolo é bastante baixo, e a presença de bibliotecas para muitas linguagens de programação permite escolher qualquer pilha de tecnologia para desenvolvimento. A garantia de entrega de mensagens distingue significativamente o MQTT de seus antecessores e permite que você não perca tempo desenvolvendo desnecessariamente seus próprios mecanismos de controle de integridade no nível da rede.

Source: https://habr.com/ru/post/pt452904/


All Articles