MQTT
MQTT - Message Queue Telemetry Transport
MQTT (Message Queue Telemetry Transport) é um protocolo de mensagens para sensores e pequenos dispositivos móveis, baseado no modelo publicador/subscritor, ideal para aplicações de Internet das Coisas, em particular para a comunicação máquina a máquina (M2M - Machine to Machine).
Referências:
- Livro (LAMPKIN etal, 2012) [1].
- Site: MQTT Essentials [2].
As aplicações de Internet das Coisas podem envolver abordagens avançadas de telemetria, de forma a poder conectar diferentes dispositivos inteligentes em atividades de sensoreamento, monitoramento e controle, além da conexão dos mesmos a Internet ou a sistemas de controle central [1].
MQTT - Conceitos básicos
- Conceitos básicos do MQTT [1]
Modelo Publicador/Subscritor
O protocolo MQTT é baseado no modelo publisher/subscriber, isto é, o princípio de publicar mensagens (publisher) e subscrever tópicos (subscriber) para receber mensagens.
- Um cliente pode subscrever tópicos e receber mensagens de atualizações quando algo for publicado sobre este tópico. Alternativamente, um cliente pode publicar mensagens relativas a um dado tópico e deixá-la disponível para os assinantes.
O modelo publisher/subscriber oferece uma alternativa ao modelo cliente/servidor. No modelo cliente/servidor o cliente se comunica diretamente o servidor num serviço fim a fim. No modelo publisher/subscriber o publicador e o subscritor não se comunicam diretamente. A comunicação é realizada por um terceiro componente, o brocker [2].
Tópicos e subscrições
As mensagens MQTT são publicadas em tópicos (topic), que são áreas de interesse.
- Os clientes, por sua vez, assinam para receber mensagens de uma dada subscrição. As subscrições podem ser explicitas, ou organizadas hierarquicamente, com o cliente usando wildcards (# ou +) para receber mensagens de uma variedade de tópicos.
- Exemplos:
- topic: /casa/terreo/temperatura
- topic: /casa/terreo/umidade
- topic: /casa/superior/temperatura
- topic: /casa/superior/umidade
- wildcard multilevel: /casa/# -> todos os sensores da casa (# multinível)
- wildcard sigle level: /casa/+/temperatura -> todos os sensores de temperatura (+ somente um nível)
Qualidade de Serviço
O MQTT define três níveis de Qualidade de Serviço (QoS):
- (0) best effort, envia a mensagem uma vez;
- (1) envia a mensagem uma ou mais vezes, podendo haver mensagens duplicadas;
- (2) assegura o recebimento de apenas uma mensagem.
Reter mensagens
O servidor MQTT pode reter mensagens publicadas no brocker, mesmo depois de enviada a todos os subscritores, e tê-las disponível para um novo subscritor deste tópico.
Sessões persistentes
Permitem a um cliente subscritor manter suas subscrições mesmo após uma desconexão. Neste caso, conexão é tratada como persistente e as subscrições do cliente continuaram ativas após a próxima conexão.
Will e Testamento
Característica também chamada LWT (Last Will and Testament) do MQTT. Quando um cliente (publicador ou subscritor) se conecta a um servidor e pode informar que possui uma will, isto é, mensagens importantes que deveriam ser publicadas em caso de desconexão involuntária.
MQTT - sensores e atuadores
O MQTT tem aplicabilidade especial para dispositivos para sensoriamento remoto [1].
- Sensores
- Sensores medem ou monitoram parâmetros do ambiente ou de um sistema e reportam a informação para humanos ou outros dispositivos ou sistemas. Com a ajuda do protocolo MQTT a informação obtida pelos sensores pode ser realizada via rede.
- Múltiplos sensores podem ser posicionados para reportar vários parâmetros e medições em diferentes localizações, dando uma visão completa das condições de operação de um dispositivo ou sistema.
- Atuadores
- Atuadores são dispositivos que atuam sobre variáveis de um sistema visando alterar seu comportamento.
O controle de um sistema normalmente envolve sensores monitorando parâmetros do sistema e atuadores visando corrigir sua operação. A ação de controle é realizada a partir de um algoritmo de controle, que pode ser executado por controlador central, ou diretamente pelos sensores/atuadores, que, neste caso, devem ter processamento no próprio sensor/atuador.
O modelo publisher/subscriber do MQTT pode ser bastante útil para interligar sensores, atuadores e sistemas de controle em diferentes tipos de aplicações, em particular àquelas que envolvem as chamadas tecnologias de Internet das Coisas.
Mensagens do protocolo MQTT [2]
O protocolo MQTT trabalha no topo da pilha de protocolos TCP/IP (Transmission Control Protocol/Internet Protocol), que são os principais protocolos da Internet.
O modelo publisher/subscriber do MQTT desacopla a mensagem enviada pelo cliente publicador (publisher) do cliente subscritor (subscriber).
O MQTT usa tópicos para determinar quais mensagens vão ser encaminhadas a cada subscriber.
- Cliente MQTT
- Tanto o publisher quanto o subscriber são clientes MQTT.
- Um cliente MQTT é qualquer dispositivo que rode a biblioteca MQTT, desde um microcontrolador até um servidor de grande porte.
- brocker MQTT
- O brocker MQTT intermedeia a comunicação entre os clientes publicadores e subscritores.
- O brocker é o responsável de receber todas as mensagens, determinar quais são os subscritores de cada mensagem, e, em seguida, encaminhar as estas mensagens aos subscritores.
- Blibliotecas MQTT
- Bibliotecas cliente MQTT estão disponíveis em diferentes linguagens de programação, como Android, Arduino, C, C++, Ct#, Go, iOS, Java, JavaScript, and .NET. Veja lista completa em MQTT wiki.
Mensagens de Conexão
Uma conexão MQTT é sempre entre um cliente e um brocker. O cliente inicia a conexão enviando uma mensagem CONNECT ao brocker, que responde com a mensagem CONNACK. A conexão é mantida até que o cliente envie uma mensagem DISCONNECT.
Cliente Brocker | ----------> | | CONNECT | | <---------- | | CONNACK |
- Detalhe das mensagens
CONNECT clientId "cliente1" cleanSession true keepAlive 60 username "user1" (opcional) passwd "1234" (opcional) lastWillTopic "topic1/will" (opcional) lastWillQoS 2 (opcional) lastWillMessage "unexpected exit" (opcional) lastWillRetain false (opcional) keepAlive 60
O clientId é um identificador único do cliente para o brocker com o qual vai se comunicar.
A flag cleanSession informa se a sessão é persistente ou não.
O username e passwd são enviados em modo texto, portanto, é aconselhável utilizá-las juntamente com transporte seguro através de autenticação de clientes com SSL.
Parâmetros lastWill (ver abaixo).
Parâmetro keepAlive (ver abaixo).
CONNACT sessionPresent false returnCode 0
O parâmetro sessionPresent informa ao cliente se o brocker já tem uma conexão persistente anterior com este cliente.
O parâmetro returnCode é o retorno com o estado da conexão, que pode ser:
- 0 Conexão aceita
- 1 Conexão recusada: versão inválida
- 2 Conexão recusada: userId rejeitada
- 3 Conexão recusada: servidor não disponível
- 4 Conexão recusada: username ou passwd inválida
- 5 Conexão recusada: não autorizado
Keep Alive
O protocolo MQTT é baseado no TCP, o qual transfere mensagens de forma confiável, ordenada e livre de erros. Entretanto, eventualmente, podem ocorrer falhas em uma conexão TCP, na qual uma das partes perde a conexão e a outra continua ativa, ficando no estado chamado half-open connection. O keep alive do MQTT visa contornar este problema.
Para manter a conexão ativa entre um cliente e o brocker, caso não haja publicação, o cliente deve enviar regularmente a mensagem PING Request ao brocker, que responde com PING Response. O parâmetro keepAlive informa o tempo em segundos que o cliente pode ficar sem se comunicar com o brocker depois de iniciada a conexão.
PINGREQ
PINGRESP
Se o brocker não recebe um PINGREQ ou algum outro pacote do cliente, o brocker fecha a conexão e envia a mensagem lastWill e testamento aos subscritores (caso este cliente tenha especificado uma LWT).
lastWill e Testamento
Característica também chamada LWT (Last Will and Testament) do MQTT. É utilizado pelo brocker para notificar clientes subscritores sobre uma desconexão involuntária de um cliente.
Quando um cliente (publicador ou subscritor) se conecta a um servidor e pode informar que possui mensagens lastWill, isto é, mensagens importantes que deveriam ser publicadas, mesmo em caso de desconexão involuntária.
Para fazer a atribuição prévia das mensagens lastWill, chamadas testamento, utiliza-se os parâmetros lastWill na mensagem CONNECT.
- Exemplo de aplicação [2]
- Informar ao sistema quando um cliente está fora de operação, por exemplo, um sensor que monitora um tópico crítico do sistema.
- Passos:
- O cliente se conecta ao brocker e informa uma lastWill, por exemplo: tópico = sensor/status, mensagem = off_line e seta flag reter mensagem;
- O cliente se conecta e publica para o mesmo tópico nova mensagem = on_line e seta flag reter mensagem;
- Enquanto o cliente estiver conectado, novos subscritores receberão a mensagem = on_line para o tópico = sensor/status;
- Caso o cliente se desconecte involuntariamente (sem a mensagem DISCONNECT) a mensagem lastWill será publicada e todos os subscritores receberão a mensagem = off_line para o tópico = sensor/status.
Mensagem para Publicação
O cliente publica mensagens assim que estabelece a conexão com o brocker. Cada mensagem contem um tópico, que é utilizado para encaminhar a mensagem aos clientes subscritores.
A mensagem de publicação é utilizada também pelo brocker para encaminhar as mensagens publicadas aos subscritores.
Mensagem de publicação:
PUBLISH packetId 0 topicName "sensor/temperatura" qos 0 retainFlag false payload "25,0" dupFlag false
- O parâmetro packetId é um identificador único para a mensagem e é utilizado para retransmitir mensagens com QoS diferente de 0. A biblioteca do cliente e/ou brocker é responsável por gerenciar os identificadores.
- O dupFlag indica que a mensagem é uma duplicata sendo retransmitida para um cliente que não enviou um reconhecimento da anterior. É utilizado para retransmitir mensagens com QoS diferente de 0.
- O parâmetro retainFlag define quando o brocker deve reter a mensagem como último valor adequado para este tópico.
Reter mensagem
A característica de reter mensagem permite ao brocker dispor do último valor adequado para este tópico (last known good value). Desta forma, caso haja novos subscritores para tópicos com mensagens retidas, eles receberão imediatamente as mensagens disponíveis. As mensagens retidas eliminam a espera por atualizações do cliente para o tópico assinado.
Publicação com Qualidade de Serviço (QoS)
O protocolo MQTT define três níveis de Qualidade de Serviço (QoS):
- (0) best effort, envia a mensagem uma vez;
- (1) envia a mensagem pelo menos uma vez, mas podem haver mensagens duplicadas, e aguarda confirmação de recebimento;
- (2) assegura o recebimento uma única mensagem e da confirmação do recebimento.
No MQTT a QoS deve considerar os dois lados da entrega da mensagem:
- A comunicação entre o cliente publicador e o brocker;
- A comunicação entre o brocker e os clientes subscritores.
A QoS é considerada separadamente. O cliente publicador define a QoS quando publica no brocker. O brocker, por sua vez, encaminha a mensagem ao cliente subscritor de acordo com a QoS definida no momento da subscrição. Caso a subscrição tenha QoS maior que o que foi publicado, utiliza-se a menor QoS.
- QoS = 0
- Serviço best-effort, sem garantia de entrega da mensagem.
Emissor Receptor Ação | --------------> | -Publica a mensagem aos subscritores | PUBLISH QoS=0 |
- QoS = 1
- A mensagem é enviada pelo menos uma vez ao receptor. O emissor armazena a mensagem até receber um reconhecimento do receptor com a mensagem PUBACK. O PUBACK utiliza o packetId da mensagem publicada para reconhecer a mensagem. Caso o emissor não receba reconhecimento num tempo apropriado a mensagem é reenviada com dupFlag = true. Se o receptor recebe uma mensagem duplicada ele responde com PUBACK e reencaminha a mensagem aos subscritores. Note que os subscritores também podem receber mensagens duplicadas.
- Cenário 1: Uma mensagem enviada:
Emissor Receptor Ação | --------------> | -Armazena a mensagem na base de dados | PUBLISH QoS=1 | -Publica a mensagem aos subscritores | <-------------- | | PUBACK |
- Cenário 2: Mais de uma mensagem enviada:
Emissor Receptor Ação | --------------> | -Armazena a mensagem na base de dados | PUBLISH QoS=1 | -Publica a mensagem aos subscritores | X-------- | | PUBACK | | --------------> | -Atualiza base de dados | PUBLISH QoS=1 | -Publica a mensagem aos subscritores | <-------------- | | PUBACK |
- QoS = 2
- É a maior QoS do MQTT. Garante a entrega de apenas uma mensagem aos subscritores . O protocolo utiliza um acordo em quatro vias entre o emissor e o receptor.
- O QoS=2 deve ser utilizado somente se não forem desejadas mensagens duplicadas.
Emissor Receptor Ação | --------------> | -Armazena e bloqueia a mensagem na base de dados | PUBLISH QoS=2 | (se houver mensagens duplicadas atualiza base de dados) | <-------------- | | PUBREC | | --------------> | -Publica a mensagem aos subscritores | PUBREL | | <-------------- | | PUBCOMP |
- A mensagem é enviada pelo emissor com PUBLISH. Caso o receptor receba a mensagem ele reconhece com PUBREC e deixa a mensagem bloqueada no servidor. Se o emissor não recebe o PUBREC num tempo apropriado ele envia novamente a mensagem com dupFlag = true. Caso o emissor receba o PUBREC ele tem a garantia que o receptor recebeu a mensagem e envia o PUBREL. Quando o receptor recebe o PUBREL ele responde com PUBCOMP e então encaminha a mensagem aos subscritores. As mensagens trocadas utilizam o packetId da mensagem publicada para reconhecimento.
Mensagens para e Subscrição
Para receber mensagens um cliente deve subscrever um dado tópico em um brocker MQTT.
SUBSCRIBE packetId 4343 (exemplo) List of Subscritions: topic "sensores_ambiente/#" qos 0 topic "sensor/alerta" qos 1
- O packetId é um identificador único para a mensagem entre o cliente e o brocker. A biblioteca do cliente e/ou brocker é responsável por gerenciar os identificadores.
- A List of Subscritions contém a lista de subscrições do cliente, cada qual contendo um tópico e a QoS. O tópico pode ser expresso de forma explícita ou de maneira hierárquica, separados por com /, e também pode utilizar wildcards (# ou +).
Cada subscrição é confirmada com SUBACK.
SUBACK packetId 4343 (exemplo) returnCode 0 returnCode 1 ...
- O packetId é o mesmo identificador da mensagem SUBSCRIBE correspondente.
- O returnCode informa o código para cada par tópico/QoS como segue:
- 0 Sucesso: máximo QoS 0
- 1 Sucesso: máximo QoS 1
- 2 Sucesso: máximo QoS 2
- 128 Falha
Cliente A Brocker Cliente B | -----------> | | | SUBSCRITE | | | <----------- | | | SUBACK | | | | <---------- | | <----------- | PUBLISH | | PUBLISH | |
Um cliente pode cancelar uma subscrição com UNSUBSCRIBE.
UNSUBSCRIBE packetId 4344 (exemplo) topic1 "/sensor/temp" topic2 "/sensor/umid" ...
- O packetId é um identificador único para a mensagem entre o cliente e o brocker. A biblioteca do cliente e/ou brocker é responsável por gerenciar os identificadores.
Reconhecimento
UNSUBACK packetId
- O packetId é o mesmo identificador da mensagem UNSUBSCRIBE correspondente.
Sessões persistentes
Quando um cliente subscritor se conecta (CONNECT) a um servidor com a flag clean session = true após ele se desconectar todas as subscrições serão removidas.
Caso o cliente subscritor se conecte com flag clean session = false (opcional) a sessão é tratada como persistente e as subscrições do cliente vão continuar após a próxima conexão.
As sessões persistentes eliminam a necessidade do cliente de subscrever todos os tópicos a cada vez qua a cada reconexão.
Com as sessões persistentes um cliente que ficou fora de serviço por um dado período poderá receber todas as mensagens que ficaram armazenadas no servidor sobre os tópicos que ele subscreve.
MQTT e Arduino
O suporte para MQTT para Arduíno é provido por uma biblioteca que pode ser obtida em: https://github.com/knolleary/pubsubclient .
Para interagir com a rede é necessário um shild Ethernet colocado sobre a placa Arduíno.
- Limitações do MQTT para Arduíno
- Suporta somente publicações com QoS=0 e subscrições com QoS=0 ou QoS=1.
- Tamanho máximo de mensagem com 128 bytes por default.
- Intervalo de keep alive de 15 s por default.
- Hardware compatível
- Shield Ethernet
- Arduíno Ethernet
- Arduíno Yun
- Arduíno Wifi
- ESP8266
- ESP32
Mosquitto
Mosquitto é um Brocker MQTT open source, que pode ser utilizado desde computadores de placa única até servidores.
O Mosquitto implementa o modelo publilsher/subscriber e pode ser utilizado em aplicações de Internet das Coisas, as quais fazem uso de sensores de baixa potência, atuadores, dispositivos móveis, microcontroladores e outros dispositivos programáveis.
O Mosquitto oferece comandos de linha como mosquitto_pub e mosquitto_sub para publicar e subscrever no brocker, respectivamente, além de bibliotecas em C para implementação de cliente MQTT.
Instalação e inicialização do Mosquitto no Ubuntu
sudo apt-get update sudo apt-get mosquitto sudo apt-get install mosquitto-clients
Depois de instalado no Ubuntu o Mosquito é automaticamente iniciado, assim como é iniciado a cada reboot. Para verificar se está rodando, pode utilizar o comando:
ps -aux|grep mosquitto
Parar, iniciar ou reiniciar Mosquitto:
service mosquitto stop service mosquitto start service mosquitto restart
Iniciar o Mosquitto com verbose dos logs de operação:
mosquitto -v
Páginas man:
man mosquitto
Porta TCP de escuta do Mosquitto
O Mosquitto de escuta por padrão na porta TCP 1883.
A porta pode ser alterada com um parâmetro na inicialização:
mosquitto -p 1888
- ou especificando no arquivo de configuração:
/etc/mosquitto/mosquitto.conf
Teste do Mosquitto
Use um terminal para subscrever um tópico:
mosquitto_sub -t "teste"
Use outro terminal para publicar uma mensagem em um tópico:
mosquitto_pub -m "Mensagem" -t "teste"
Usuários e senhas podem ser configurados para uso no Mosquito, ver [3] [4].
Ver detalhes e exemplos destes comandos em:
man mosquitto_pub man mosquitto_sub
Analise do protocolo MQTT e Mosquitto com Wireshark
Para a análise do protocolo MQTT foi utilizado as seguintes ferramentas:
- mosquitto: rodando no localhost Ubuntu 18.04 (IP 192.168.0.13);
- wireshark: rodando também no localhost;
- mosquitto_sub: executado em um linux Alpine rodando em um contêiner Docker (IP 172.17.0.2);
- mosquitto_pub: executado em um linux Alpine rodando em um contêiner Docker (IP 172.17.0.3).
Montagem dos contêineres Docker
Ver nos links informações sobre Docker e como rodar máquinas linux Alpine.
Rodar duas máquinas alpine no Docker:
docker run -dit --name alpine1 alpine ash docker run -dit --name alpine2 alpine ash
Verificar os contêineres iniciados:
docker container ls
Verificar a configuração de rede:
docker network inspect bridge
- Note que alpine1 e alpine2 pertencem a sub-rede 172.17.0.0/16 e gateway 172.17.0.1.
- Este gateway conecta a sub-rede do Docker ao computador hospedeiro e vice-versa. Ver roteamento no hospedeiro com:
route -n
Usar o terminal de cada alpine para instalar o mosquitto-clients:
docker attach alpine1
- Para abrir o terminal da alpine1
apk update apk add mosquitto-clients
- Para instalar pacotes na alpine1
- Repetir o processo para a alpine2
CTRL-p CTRL-q
- Para sair do terminal
Realização do experimento
- Passos
- Realizado em computador com sistema operacional Ubuntu 18.04.
- Iniciar o mosquitto.
- Iniciar o analisador de pacotes wireshark:
- configurar captura para o endereço do gateway do docker (172.17.0.1);
- configurar filtro para o protocolo mqtt.
- Abrir um terminal na alpine1 para executar o mosquitto_sub:
mosquitto_sub -t "topico"
- Observar no wireshark os pacotes capturados.
- Abrir um terminal na alpine2 para executar o mosquitto_pub:
mosquitto_pub -m "mensagem" -t "topico"
- Observar no wireshark os pacotes capturados.
- Aguardar um tempo e verificar a captura de pacotes de PINGREC e PINGRESP no wireshark que visam manter a conexão ativa (keep alive).
- No terminal da alpine1 realizar CTRL-C para cancelar a subscrição do tópico.
- Observar no Wireshark os pacotes capturados.
Análise das mensagens do protocolo MQTT capturadas
- Saída do Wireshark
- Obtida com comando Statistics/Flow Graph.
- Análise dos pacotes capturados
- Após a execução do comando:
mosquitto_sub -t "topico"
- Foram capturadas as mensagens MQTT entre o cliente subscritor (172.17.0.2) e o brocker (192.168.0.13):
Connect Command Connect Ack Subscribe Request Subscribe Ack
- Sequência de mensagens de conexão, reconhecimento, subscrição e reconhecimento.
- Note que as mensagens estão todas na marca de tempo 6.45....
- Note que o cliente usa porta 39550 e o brocker usa porta 1883.
- Após a execução do comando:
mosquitto_pub -m "mensagem" -t "topico"
- Foram capturadas as mensagens MQTT entre o cliente publicador (172.17.0.3) e o brocker (192.168.0.13):
Connect Command Connect Ack Publish Message Publish Req Disconnect Req
- Sequência de mensagens de conexão, reconhecimento, publicação, reconhecimento e desconexão.
- Note que o cliente usa porta 52856 e o brocker usa porta 1883.
- Note também que o cliente publicador se desconecta após a publicação de sua mensagem.
- Na sequência foi capturada mensagem entre o o brocker (192.168.0.13) e o cliente subscritor (172.17.0.2):
Publish Message
- Esta segunda publicação refere-se a publicação do brocker ao subscritor (porta 39550).
- Note que não houve mensagem de conexão, pois o subscritor já estava conectado.
- Após um tempo de 60s no subscritor tivemos um sequência de keep alive.
Ping Request Ping Response
- Marca de tempo 65,99...
- Note que as portas origem e destino são as mesmas do cliente subscritor.
- Por fim, após o CTRL-C no subscritor tivemos a conexão encerrada.
Disconnect Req
Logs do servidor Mosquitto
No servidor onde foi executado o Mosquito com comando:
mosquitto -v
Produziu-se os seguintes logs:
$ mosquitto -v 1586286914: mosquitto version 1.6.8 starting 1586286914: Using default config. 1586286914: Opening ipv4 listen socket on port 1883. 1586286914: Opening ipv6 listen socket on port 1883. 1586286950: New connection from 172.17.0.2 on port 1883. 1586286950: New client connected from 172.17.0.2 as mosq-qBvzZOWQ3LYlYmmIad (p2, c1, k60). 1586286950: No will message specified. 1586286950: Sending CONNACK to mosq-qBvzZOWQ3LYlYmmIad (0, 0) 1586286950: Received SUBSCRIBE from mosq-qBvzZOWQ3LYlYmmIad 1586286950: topico (QoS 0) 1586286950: mosq-qBvzZOWQ3LYlYmmIad 0 topico 1586286950: Sending SUBACK to mosq-qBvzZOWQ3LYlYmmIad 1586286970: New connection from 172.17.0.3 on port 1883. 1586286970: New client connected from 172.17.0.3 as mosq-IRSh0LaxjMfYDMRrLF (p2, c1, k60). 1586286970: No will message specified. 1586286970: Sending CONNACK to mosq-IRSh0LaxjMfYDMRrLF (0, 0) 1586286970: Received PUBLISH from mosq-IRSh0LaxjMfYDMRrLF (d0, q0, r0, m0, 'topico', ... (8 bytes)) 1586286970: Sending PUBLISH to mosq-qBvzZOWQ3LYlYmmIad (d0, q0, r0, m0, 'topico', ... (8 bytes)) 1586286970: Received DISCONNECT from mosq-IRSh0LaxjMfYDMRrLF 1586286970: Client mosq-IRSh0LaxjMfYDMRrLF disconnected. 1586287009: Received PINGREQ from mosq-qBvzZOWQ3LYlYmmIad 1586287009: Sending PINGRESP to mosq-qBvzZOWQ3LYlYmmIad 1586287015: Received DISCONNECT from mosq-qBvzZOWQ3LYlYmmIad 1586287015: Client mosq-qBvzZOWQ3LYlYmmIad disconnected.
- Note que os logs no servidor correspondem as mensagens trocadas pelo protocolo MQTT.
Outros cenários de análise do protocolo MQTT
Subscrição e publicação com QoS=1
Comandos para subscrição e publicação:
mosquitto_sub -h 192.168.0.13 -t "topico" -q 1 mosquitto_pub -h 192.168.0.13 -m "mensagem" -t "topico" -q 1
- Análise dos pacotes capturados
- Cada mensagem de publicação (Publish) é seguida pelo reconhecimento (Publish Ack).
Subscrição e publicação com QoS=2
Comandos para subscrição e publicação:
mosquitto_sub -h 192.168.0.13 -t "topico" -q 2 mosquitto_pub -h 192.168.0.13 -m "mensagem" -t "topico" -q 2
- Análise dos pacotes capturados
- Cada mensagem de publicação (Publish) é seguida por mensagem de publicação recebida (Publish Received), depois publicação liberada (Publish Release) e publicação completa (Publish Complete).
Reter Mensagens Publicadas
Caso o cliente publique com o retainFlag = true o brocker vai reter a mensagem e publicá-la a um cliente subscritor assim que o mesmo realize a subscrição deste tópico.
Comandos para subscrição e publicação:
mosquitto_pub -h 192.168.0.13 -m "mensagem" -t "topico" -q 1 -r mosquitto_sub -h 192.168.0.13 -t "topico" -q 1
Mensagem de publicação:
MQ Telemetry Transport Protocol, Publish Message Header Flags: 0x33, Message Type: Publish Message, QoS Level: At least once delivery (Acknowledged deliver), Retain 0011 .... = Message Type: Publish Message (3) .... 0... = DUP Flag: Not set .... .01. = QoS Level: At least once delivery (Acknowledged deliver) (1) .... ...1 = Retain: Set Msg Len: 18 Topic Length: 6 Topic: topico Message Identifier: 1 Message: mensagem
- Análise dos pacotes capturados
- Nas primeiras mensagens capturadas o cliente se conectou, publicou uma mensagem (QoS=1) e se desconectou. Depois um cliente se conectou, subscreveu u tópico (QoS=1). Loco em seguida o brocker publicou a mensagem retida ao cliente.
Subscrever com Sessão Persistente
Caso o cliente subscritor se conecte com flag clean session = false a sessão é tratada como persistente e as subscrições do cliente vão continuar após a próxima conexão.
Comandos executados para subscrição e publicação:
mosquitto_sub -h 192.168.0.13 -t "topico" -q 1 -c mosquitto_pub -h 192.168.0.13 -m "mensagem1" -t "topico" -q 1
- Subscritor foi desconectado com CTRL-C
mosquitto_pub -h 192.168.0.13 -m "mensagem2" -t "topico" -q 1 mosquitto_sub -h 192.168.0.13 -t "topico" -q 1 -c
- Análise dos pacotes capturados
- Na primeira figura, na marca de tempo 0.0... um cliente subscritor se conecta e subscreve um tópico (QoS=1) com sessão persistente.
- Na marca de tempo 12.8... o cliente publicador se conecta e publica uma mensagem e se desconecta e o brocker também publica a mensagem ao subscritor.
- Na marca de tempo 21.3... o cliente subscritor se desconecta.
- Na marca de tempo 31.7... o cliente publicador publica outra mensagem. Note que neste momento o cliente subscritor estava desconectado.
- Na marca de tempo 42.5... o cliente subscritor volta a se conectar. Como vemos nas trocas de mensagens continuam na segunda figura (inicio marcado em azul), imediatamente o brocker publica a mensagem da sessão persistente, recebida quando o mesmo estava desconectado.
LastWill e Testamento
O cenário para testar as mensagens lastWillfoi inspirado no exemplo de aplicação descrito anteriormente na seção Will e Testamento.
- Passos do experimento
- O Cliente 1 (IP 172.17.0.2) se conectou ao brocker, iniciou publicação com repetição a cada 5s para o tópico = sensor/status e mensagem = on_line e flag setado para reter mensagem; também informou lastWill como tópico = sensor/status, mensagem = off_line e setou flag reter mensagem:
mosquitto_pub -h 192.168.0.13 -m "on-line" -t "sensor1/status" -r --repeat 20 --repeat-delay 5 --will-topic "sensor1/status" --will-payload "off-line" --will-retain
- O Cliente 2 (IP 172.17.0.3) se conectou ao brocker e subscreveu o tópico = sensor/status:
mosquitto_sub -h 192.168.0.13 -t "sensor1/status"
- Após algumas publicações a cada 5s, o Cliente 1 foi desconectado de forma involuntária, parando a máquina em que estava rodando no Docker a partir de um terminal do localhost:
docker stop alpine1
- Análise dos pacotes capturados
- Na marca de tempo 35,0... o cliente 1 se conecta, publica para o tópico = sensor/status a mensagem = on_line e informa lastWill;
- Na marca de tempo 40,0... o cliente 1 publica novamente para o tópico = sensor/status a mensagem = on_line;
- Na marca de tempo 45,0... o cliente 1 publica novamente para o tópico = sensor/status a mensagem = on_line;
- Na marca de tempo 46,6... o cliente 2 se conecta e subscreve o tópico = sensor/status e recebe publicação da mensagem = on_line que estava retida;
- Nas marcas de tempo 50,0..., 55,0... e 60,0..., o cliente 1 publica novamente para o tópico = sensor/status a mensagem = on_line e o brocker a encamimnha para o cliente 2 (veja mensagem abaixo);
No. Time Source Destination Protocol Length Info 55 60.046941293 192.168.0.13 172.17.0.3 MQTT 91 Publish Message [sensor1/status] MQ Telemetry Transport Protocol, Publish Message Header Flags: 0x30, Message Type: Publish Message, QoS Level: At most once delivery (Fire and Forget) Msg Len: 23 Topic Length: 14 Topic: sensor1/status Message: on-line
- Na marca de tempo 64,4... a máquina do cliente 1 foi desconectada involuntariamente e o brocker publica para o cliente 2 a mensagem = off_line (veja mensagem abaixo).
No. Time Source Destination Protocol Length Info 60 64.476755451 192.168.0.13 172.17.0.3 MQTT 92 Publish Message [sensor1/status] MQ Telemetry Transport Protocol, Publish Message Header Flags: 0x30, Message Type: Publish Message, QoS Level: At most once delivery (Fire and Forget) Msg Len: 24 Topic Length: 14 Topic: sensor1/status Message: off-line
Terminal do cliente 2:
# mosquitto_sub -h 192.168.0.13 -t "sensor1/status" on-line on-line on-line on-line off-line
- Observações sobre o lastWill
- Caso o cliente 1 fosse desconectado normalmente (CTRL-C) uma mensagem de DISCONNECT seria enviada ao brocker e a mensagem lastWill não seria enviada.
- Com uma desconexão involuntária a mensagem lastWill é enviada.
- Uma desconexão involuntária pode ser um problema na rede, erro no cliente, ausência de PINGREC etc. Simulamos derrubando a máquina do cliente.
Mosquitto em contêiner Docker
Rodando o Mosquitto em um contêiner Docker com Alpine Linux [5]
- Comando para rodar o mosquitto no contêiner
docker run -p 1883:1883 --name mosquitto trafex/alpine-mosquitto
- Roda o contêiner para escutar na porta 1883 padrão do host, com nome mosquitto.
- trafex/alpine-mosquitto é o nome da imagem.
O servidor Mosquitto fica acessível como se estivesse rodando na máquina que está hospedando o Docker.
- Subscrever tópicos e e publicar mensagens
Usando o cliente para subscrever um tópico:
docker exec -ti mosquitto mosquitto_sub -h 127.0.0.1 -v -t '#'
- O comando exec executa o mosquitto_sub no contêiner rodando.
Usando o cliente para publicar no tópico:
docker exec -ti mosquitto mosquitto_pub -h 127.0.0.1 -t 'hello' -m 'world'
- O comando exec executa o mosquitto_pub no contêiner rodando.
Referências
- ↑ 1,0 1,1 1,2 1,3 Valerie Lampkin; Weng Tat Leong; Leonardo Olivera; Sweta Rawat; Nagesh Subrahmanyam; Rong Xiang. Building Smarter Planet Solutions with MQTT and IBM WebSphere MQ Telemetry, ibm.com/redbooks, 2012.
- ↑ 2,0 2,1 2,2 2,3 MQTT Essentials: The Ultimate Kickstart For MQTT Beginners, https://www.hivemq.com/mqtt-essentials/.
- ↑ Fernando Veiga. Instalar MQTT-Broker no Linux, Things Hackers Team, 2018.
- ↑ Faz-B. Instalando, testando e conhecendo o MQTT no Ubuntu, 2017.
- ↑ Mosquitto Docker container, Trafex, 2019.
Evandro.cantu (discussão) 11h27min de 25 de março de 2020 (-03)