MQTT
O MQTT é um protocolo de troca de mensagens entre computadores. Ele é muito leve e eficiente.
No MQTT temos 3 pessoas envolvidas:
Publisher
Os publishers são quem criam as mensagens e as enviam.
Subscriber
Os subscribers são quem recebem as mensagens dos publishers.
Broker
O broker é quem faz o meio de campo. Os publishers nunca se comunicam com os subscribers diretamente, o broker é sempre quem se comunica. O publisher envia mensagem para o broker. O subscriber se conecta com o broker e pede para escutar mensagens.
Mensagens e garantias de entrega
O MQTT pode ter 3 tipos de garantia de entrega, também chamados de QoS (Quality of Service). É importante dizer que o protocolo MQTT não garante que as mensagens sejam entregues em caso de queda de conexão
QoS 0
Não há nenhuma garantia de que a mensagem será entregue. Chamado de "Publish and forget". Tem custo baixo computacional e de tráfego de rede.
QoS 1
O Publisher aguarda uma confirmação do broker de que a mensagem foi entregue com sucesso. As mensagens podem ser enviadas de forma duplicada. Tem custo médio computacional e detráfego de rede.
QoS 2
O Publisher aguarda uma confirmação do broker de que a mensagem foi entregue com sucesso. As mensagens são recebidas apenas uma vez pelo broker (sem duplicação). Tem o maior custo computacional e de tráfego de rede.
Clientes MQTT
Eclipse Paho
É o cliente MQTT mais usado (pelo menos no maven repository).
Confiabilidade na entrega das mensagens pelo Paho
Se você pretende que suas mensagens sejam entregues com confiança para o broker, você precisa fazer tudo isso na mão. Apesar do protocolo MQTT "garantir entregas das mensagens", essa garantia é uma garantia a nível de rede, e não a nível de software do cliente. Vou dar alguns exemplos:
Em uma conexão síncrona, memory persistence, se a conexão com o broker cair no meio da transmissão mas voltar logo em seguida, você receberá exceptions, sua conexão ficará inutilizada e você não poderá mais enviar mensagens. A primeira exception é a de que houve uma reconexão com o banco. As seguintes são de que houveram tentativas de enviar mensagens, mas elas falharam porque a conexão não existe.
Conexão perdida (32109) - java.net.SocketException: Connection reset at org.eclipse.paho.client.mqttv3.internal.CommsReceiver.run(CommsReceiver.java:189) at java.lang.Thread.run(Thread.java:745) Caused by: java.net.SocketException: Connection reset at java.net.SocketInputStream.read(SocketInputStream.java:210) at java.net.SocketInputStream.read(SocketInputStream.java:141) at java.net.SocketInputStream.read(SocketInputStream.java:224) at java.io.DataInputStream.readByte(DataInputStream.java:265) at org.eclipse.paho.client.mqttv3.internal.wire.MqttInputStream.readMqttWireMessage(MqttInputStream.java:92) at org.eclipse.paho.client.mqttv3.internal.CommsReceiver.run(CommsReceiver.java:136) ... 1 more O cliente não está conectado (32104) at org.eclipse.paho.client.mqttv3.internal.ExceptionHelper.createMqttException(ExceptionHelper.java:31) at org.eclipse.paho.client.mqttv3.internal.ClientComms.sendNoWait(ClientComms.java:203) at org.eclipse.paho.client.mqttv3.MqttAsyncClient.publish(MqttAsyncClient.java:1251) at org.eclipse.paho.client.mqttv3.MqttClient.publish(MqttClient.java:570) at PahoMQTTPublisher.main(PahoMQTTPublisher.java:77) O cliente não está conectado (32104) at org.eclipse.paho.client.mqttv3.internal.ExceptionHelper.createMqttException(ExceptionHelper.java:31) at org.eclipse.paho.client.mqttv3.internal.ClientComms.sendNoWait(ClientComms.java:203) at org.eclipse.paho.client.mqttv3.MqttAsyncClient.publish(MqttAsyncClient.java:1251) at org.eclipse.paho.client.mqttv3.MqttClient.publish(MqttClient.java:570) at PahoMQTTPublisher.main(PahoMQTTPublisher.java:77)
Em uma conexão assíncrona, você precisa adivinhar o momento que a conexão é estabelecidade antes de começar a enviar mensagens, se não receberá a exception abaixo. Uma solução é usar callbacks antes de começar a enviar mensagens. Veja a documentação do MqttAsyncClient.setCallback e a classe MqttCallback.
O cliente não está conectado (32104) at org.eclipse.paho.client.mqttv3.internal.ExceptionHelper.createMqttException(ExceptionHelper.java:31) at org.eclipse.paho.client.mqttv3.internal.ClientComms.sendNoWait(ClientComms.java:203) at org.eclipse.paho.client.mqttv3.MqttAsyncClient.publish(MqttAsyncClient.java:1251) at org.eclipse.paho.client.mqttv3.MqttAsyncClient.publish(MqttAsyncClient.java:1224) at PahoMQTTPublisher.main(PahoMQTTPublisher.java:77)
Em uma conexão assíncrona, com maxInflight 300 (número máximo de mensagens enviadas sem receber confirmação), ao enviar 1000 mensagens de uma só vez (usando um for loop), ele envia 300 mensagens mas descarta as outras 700. Pra cada uma dessas descartadas ele joga exception:
Muitas publicações em andamento (32202) at org.eclipse.paho.client.mqttv3.internal.ClientState.send(ClientState.java:524) at org.eclipse.paho.client.mqttv3.internal.ClientComms.internalSend(ClientComms.java:161) at org.eclipse.paho.client.mqttv3.internal.ClientComms.sendNoWait(ClientComms.java:191) at org.eclipse.paho.client.mqttv3.MqttAsyncClient.publish(MqttAsyncClient.java:1251) at org.eclipse.paho.client.mqttv3.MqttAsyncClient.publish(MqttAsyncClient.java:1224) at PahoMQTTPublisher.main(PahoMQTTPublisher.java:77)
Como o Paho lida com persistência de mensagens?
https://stackoverflow.com/questions/21269331/mqtt-paho-trying-to-publish-while-broker-is-unreachable
https://github.com/RubyDevInc/paho.mqtt.ruby/issues/24
https://groups.google.com/d/msg/mqtt/bqmJoNpk_Gc/yxVlDgmJDAAJ
https://stackoverflow.com/questions/38737217/how-to-store-data-mqtt-when-offline-and-send-them-when-online
FuseSource MQTT Client
ActiveMQ MQTT