I'm using the MQTT Java library by Paho to detect the status of some devices. I'm facing a weird problem, because every 5 minutes I got a Connection lost error. BTW, with the usage of the reconnect method it works well, but why I got this strange fact? I'm using these lines of code within a Java EE in #Singleton component, which starts at boot.
String id = MqttAsyncClient.generateClientId();
System.out.println("Mqtt " + id + " " + uuid + " " + topics);
MqttClient client = new MqttClient(mqttSettings.generateURI(), id, new MemoryPersistence());
MqttConnectOptions connOpts = new MqttConnectOptions();
connOpts.setCleanSession(true);
connOpts.setAutomaticReconnect(true);
connOpts.setUserName(mqttSettings.getUsername());
connOpts.setPassword(mqttSettings.getPassword().toCharArray());
if (statement) {
setStatement(uuid, connOpts);
}
client.setCallback(callback);
client.connect(connOpts);
System.out.println("Connected? "+client.isConnected());
client.subscribe(topics);
if (statement) {
try {
System.out.println("Publishing installation status online...");
publishOnline(client);
} catch (MqttException e) {
System.out.println("MQTT local");
e.printStackTrace();
}
}
return client;
Related
We are building a project in Java which is using MQTT to communicate with other services using Paho client library. While running the application, I observed that if the broker is down, Paho is not caching failed outbound messages.
Is there a way to make Paho cache failed outbound messages?
I am using Paho version 1.2.5
org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.2.5
Here is how I have configured it:
public void connect(MqttCallback mqttCallback, int maxInflight) {
try {
persistence = new MqttDefaultFilePersistence(mqttPersistenceLocation);
mqttClient = new MqttAsyncClient(broker, clientId, persistence);
connOpts = new MqttConnectOptions();
// always set cleanSession to false if QoS 1 or 2 is used.
connOpts.setCleanSession(false);
connOpts.setAutomaticReconnect(true);
connOpts.setMaxInflight(maxInflight);
mqttClient.setCallback(mqttCallback);
LOGGER.info("Connecting to broker: " + broker + " with maxInflight: " + maxInflight);
mqttClient.connect(connOpts).waitForCompletion();
LOGGER.info("Connected");
} catch (Exception e) {
LOGGER.error("Error while connecting to MQTT:" + e);
}
}
I wrote some logic which represent near 200 websocet connection with exchange at the same time.I use third party api and it based on org.eclipse.jetty.websocket.api. I have this method which i had to override.
try {
URI uri = new URI(websocketBaseUrl + url);
SslContextFactory sslContextFactory = new SslContextFactory();
sslContextFactory.setTrustAll(true);
WebSocketClient client = new WebSocketClient(sslContextFactory);
client.setMaxIdleTimeout(0);
client.start();
return client.connect(adapter, uri).get();
} catch (URISyntaxException e) {
throw new BinanceApiException("URL Syntax error: " + e.getMessage());
} catch (Throwable e) {
throw new BinanceApiException("Websocket error: " + e.getMessage());
}
I added setIdleTimeout to it so that the connection is not lost when i don't recieve information for a long time.
Exchange close connection one time a day but for 2,3 sometimes 4 days it have been reconnected.But finally i get this:
java.nio.channels.ClosedChannelException: null at
org.eclipse.jetty.io.WriteFlusher.onClose(WriteFlusher.java:507) at
org.eclipse.jetty.io.ssl.SslConnection$DecryptedEndPoint.onIncompleteFlush(SslConnection.java:527)
at
org.eclipse.jetty.io.AbstractEndPoint$2.onIncompleteFlush(AbstractEndPoint.java:54)
at org.eclipse.jetty.io.WriteFlusher.write(WriteFlusher.java:331) at
org.eclipse.jetty.io.AbstractEndPoint.write(AbstractEndPoint.java:372)
at
org.eclipse.jetty.websocket.common.io.FrameFlusher$Flusher.flush(FrameFlusher.java:153)
at
org.eclipse.jetty.websocket.common.io.FrameFlusher$Flusher.process(FrameFlusher.java:217)
at
org.eclipse.jetty.util.IteratingCallback.processing(IteratingCallback.java:241)
at
org.eclipse.jetty.util.IteratingCallback.iterate(IteratingCallback.java:224)
at
org.eclipse.jetty.websocket.common.io.FrameFlusher.enqueue(FrameFlusher.java:382)
at
org.eclipse.jetty.websocket.common.io.AbstractWebSocketConnection.outgoingFrame(AbstractWebSocketConnection.java:614)
at
org.eclipse.jetty.websocket.client.io.WebSocketClientConnection.outgoingFrame(WebSocketClientConnection.java:72)
at
org.eclipse.jetty.websocket.common.io.AbstractWebSocketConnection.onConnectionStateChange(AbstractWebSocketConnection.java:473)
at
org.eclipse.jetty.websocket.common.io.IOState.notifyStateListeners(IOState.java:184)
at
org.eclipse.jetty.websocket.common.io.IOState.onReadFailure(IOState.java:498)
at
org.eclipse.jetty.websocket.common.io.AbstractWebSocketConnection.readParse(AbstractWebSocketConnection.java:666)
at
org.eclipse.jetty.websocket.common.io.AbstractWebSocketConnection.onFillable(AbstractWebSocketConnection.java:511)
at
org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:279)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:104)
at
org.eclipse.jetty.io.ssl.SslConnection.onFillable(SslConnection.java:289)
at
org.eclipse.jetty.io.ssl.SslConnection$3.succeeded(SslConnection.java:149)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:104)
at
org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:124)
at
org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:247)
at
org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.produce(EatWhatYouKill.java:140)
at
org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:131)
at
org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:243)
at
org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:679)
at
org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:597)
at java.lang.Thread.run(Thread.java:748)
I find this question on stackoverflow but i can't see clear answer. Pls help.Thanks in advance.
If you want the connection to stay open if idle, you should configure your client this way:
client.setMaxIdleTimeout(Long.MAX_VALUE);
Setting maxIdleTimeout to 0 would have the opposite effect: Closing the connection as soon as it becomes idle.
I have a board that sends jsons with telemetry to Azure IoT hub (using http). I want to read telemetry data with my android device. I looked some examples of reading messages from IoT hub for android, but I found only how to read them from "Cloud to device feedback" endpoint. So now my application looks like:
Json from the board ----> "Events" endpoint ---> Function application that resending json to "Cloud to device feedback" endpoint
-----> "Cloud to device feedback" endpoint ----> Android device.
I'm a beginner in Azure, so I'm sure that exists smarter way to do that. (Json from the board ----> "Events" endpoint ---> Android device). I did it on my desktop, but looks like android doesn't work with some libraries from desktop project.
Does anybody know how can I do it? (maybe some guides or lessons)
Desktop version
Part of android code:
public void btnReceiveOnClick(View v) throws URISyntaxException, IOException
{
System.out.println("Receiving:");
Button button = (Button) v;
// Comment/uncomment from lines below to use HTTPS or MQTT protocol
//IotHubClientProtocol protocol = IotHubClientProtocol.HTTPS;
IotHubClientProtocol protocol = IotHubClientProtocol.MQTT;
DeviceClient client = new DeviceClient(connString, protocol);
if (protocol == IotHubClientProtocol.MQTT)
{
MessageCallbackMqtt callback = new MessageCallbackMqtt();
Counter counter = new Counter(0);
client.setMessageCallback(callback, counter);
} else
{
MessageCallback callback = new MessageCallback();
Counter counter = new Counter(0);
client.setMessageCallback(callback, counter);
}
try
{
client.open();
} catch (Exception e2)
{
System.out.println("Exception while opening IoTHub connection: " + e2.toString());
}
try
{
Thread.sleep(1000);
} catch (InterruptedException e)
{
e.printStackTrace();
}
client.closeNow();
try {
....
}catch (JSONException je){
....
}
}
// Our MQTT doesn't support abandon/reject, so we will only display the messaged received
// from IoTHub and return COMPLETE
static class MessageCallbackMqtt implements com.microsoft.azure.sdk.iot.device.MessageCallback
{
public IotHubMessageResult execute(Message msg, Object context)
{
responce = new String(msg.getBytes(), Message.DEFAULT_IOTHUB_MESSAGE_CHARSET);
Counter counter = (Counter) context;
System.out.println(
"[from MessageCallbackMqtt] Received message " + counter.toString()
+ " with content: " + responce);
counter.increment();
return IotHubMessageResult.COMPLETE;
}
}
static class EventCallback implements IotHubEventCallback
{
public void execute(IotHubStatusCode status, Object context)
{
Integer i = (Integer) context;
System.out.println("[from EventCallback] IoT Hub responded to message " + i.toString()
+ " with status " + status.name());
}
}
static class MessageCallback implements com.microsoft.azure.sdk.iot.device.MessageCallback
{
public IotHubMessageResult execute(Message msg, Object context)
{
Counter counter = (Counter) context;
System.out.println(
"Received message " + counter.toString()
+ " with content: " + new String(msg.getBytes(), Message.DEFAULT_IOTHUB_MESSAGE_CHARSET));
int switchVal = counter.get() % 3;
IotHubMessageResult res;
switch (switchVal)
{
case 0:
res = IotHubMessageResult.COMPLETE;
break;
case 1:
res = IotHubMessageResult.ABANDON;
break;
case 2:
res = IotHubMessageResult.REJECT;
break;
default:
// should never happen.
throw new IllegalStateException("Invalid message result specified.");
}
System.out.println("Responding to message " + counter.toString() + " with " + res.name());
counter.increment();
return res;
}
}
You can refer to this document.It shows how to read the telemetry from you IoT Hub with Java.In the ReadDeviceToCloudMessages.java sample, it connects to the service-side Events endpoint on your IoT Hub and receives the device-to-cloud messages.
BTW, you can get the eventHubsCompatibleEndpoint, eventHubsCompatiblePath and iotHubSasKey from Azure Portal simply. The eventHubsCompatibleEndpoint is in this format:
sb://xxxxxxxxxxxxxx.servicebus.windows.net/
I am implementing MQTT Client with Eclipse Paho and has some problems:
Both Publisher and Subscriber connect to broker with qos = 1 and setCleanSession =
false.
My flow:
Connect Subscriber and Publisher to broker, it's ok.
Disconnect Subscriber (I force stop My Project which include Subscriber ), Publisher continuing publishing message.
Reconnect Subscriber -> it cannot connect and throw exception: connectionLost.
If i set qos of Subscriber = 0, it not throw exception but The client does not receive messages sent by the publisher while the subscriber is offline, which I do not want
Can someone help me with this?
This is my code in subcriber
try {
// Create an Mqtt client
MqttAsyncClient mqttClient
= new MqttAsyncClient("tcp://" + swmConfig.getMqttApiLink(), "MeasureTransactionApi");
// new MqttAsyncClient(serverURI, clientId, persistence)
MqttConnectOptions connOpts = new MqttConnectOptions();
connOpts.setUserName(swmConfig.getMqttUsername());
connOpts.setPassword(swmConfig.getMqttPassword().toCharArray());
connOpts.setCleanSession(false);
// Connect to RabbitMQ Broker
log.info("Connecting to RabbitMQ broker: " + swmConfig.getMqttApiLink());
IMqttToken conToken = mqttClient.connect(connOpts);
conToken.waitForCompletion(10000);
if (!conToken.isComplete() || conToken.getException() != null) {
log.info("Error connecting: " + conToken.getException());
System.exit(-1);
}
log.info("Connected");
// Latch used for synchronizing b/w threads
final CountDownLatch latch = new CountDownLatch(1);
// Callback - Anonymous inner-class for receiving messages
mqttClient.setCallback(new MqttCallback() {
public void messageArrived(String topic, MqttMessage message) {
String time = new Timestamp(System.currentTimeMillis()).toString();
log.info("\nReceived a Message from RabbitMQ Broker" + "\n\tTime: " + time
+ "\n\tTopic: " + topic + "\n\tMessage: "
+ new String(message.getPayload()) + "\n\tQoS: "
+ message.getQos() + "\n");
handleMQTTMessageService.handleMessageArrived(message);
}
public void connectionLost(Throwable cause) {
log.info("Connection to RabbitMQ broker lost!" + cause.getMessage());
latch.countDown();
}
public void deliveryComplete(IMqttDeliveryToken token) {
log.info("deliveryComplete");
}
});
// Subscribe client to the topic filter with QoS level of 1
log.info("Subscribing client to topic: " + topic);
IMqttToken subToken = mqttClient.subscribe(topic, 1);
subToken.waitForCompletion(10000);
if (!subToken.isComplete() || subToken.getException() != null) {
log.info("Error subscribing: " + subToken.getException());
System.exit(-1);
}
} catch (MqttException me) {
log.error("Error:", me);
}
QOS is independent for publishers and subscribers.
To ensure delivery to the subscribing client you need to subscribe at greater than QOS 0.
What happens to QOS 0 subscriptions depends on the broker, by default most will not queue messages for QOS 0 subscriptions, but mosquitto can be forced to with the queue_qos0_messages configuration flag
i have a database for practice at phpMyAdmin. i use XAMPP. I am in very early stages of learing about the conection with a database. I followa tutorial and i think i am understanding the concept and everything is cool. But i stepped on a problem that despite the fact that there are answers on the internet, i cant solve it. here is my code:
import java.sql.*;
public class DBConnect {
private Connection connection;
private Statement statement;
private ResultSet result;
public DBConnect(){
try {
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection("jdbc:mysql://localhost:1234/practicedb"); //code stucks here and after some minutes it is throwing an exception
System.out.println("Connected");//this is never executed.
statement = connection.createStatement();
} catch (Exception ex) {
System.out.print("Error in Constractor: "+ex);
}
}
public void getData() {
try {
String query = "select * from cars";
result = statement.executeQuery(query);
while (result.next()) {
String name = result.getString("carName");
String id = result.getString("carID");
String modelNum = result.getString("modelNumber");
System.out.println("Car name: " + name + ", " + "Car ID: " + id + ", " + "Car model number: " + modelNum);
}
} catch (Exception ex) {
System.out.println(ex);
}
}
}
In the main class i create an instance of the class and then call the getData().
The code stucks in that line:
connection = DriverManager.getConnection("jdbc:mysql://localhost:1234/practicedb");
And it throws that:
com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure
The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.java.lang.NullPointerException
This similar question was answered here: answer
But the suggestions are poor. I have tried flushing dns. I checked the URL and this is the one i connect to the database on phpmyadmin. i changed localhost to my ip adress. but all those just dont work.
I would really appreciate help. Is the first step on managing to receive that knowledge and i actually cant proceed at the moment. Thank you :)
i noticed that if i change the localhost:1234 to a random one like localhost:5432 it is throwing the error immediatelly. But when i have it on 1234(which i the port i have choosen through xampp config) then the programm runs for round about 5 minutes before it got terminated with the exception
Usually MySQL listens on the default port 3306.
If your database is named practicedb then your code should look like this:
private Connection connection;
try {
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/practicedb");
System.out.println("Connected");
} catch (Exception ex) {
System.out.print("Error creating connection: "+ex);
}