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 TrendsConceitos 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ó centralNo 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 dadosAo 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
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 criptografadoO 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 nuvemA 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.