Currently this is not supported in paho java library, but I need this functionality in our application. For example, on application startup, we didn't have network connection, but after 30 seconds or so, we established connection successfully so I want my client to connect automatically.
My question is - what would be best approach to accomplish this? What I tried so far is to try to reconnect if something goes wrong during connect method. And since we use RxJava I have scheduled execution of the same method which is responsible for client connection. It will be easier if I paste the code.
private void connect(String brokerUrl) {
try {
LOG.info("Connecting to the broker...");
mqttClient.connect(connectionOptions, "Connecting", new IMqttActionListener() {
#Override
public void onSuccess(IMqttToken asyncActionToken) {
LOG.info("Successfully conected to the broker.");
}
#Override
public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
LOG.error("Failed to connect to broker. Trying to reconnect in {} milliseconds...", connectionRetryTimeout, exception);
// try to reconnect in few seconds
Schedulers.io().scheduleDirect(() -> connect(brokerUrl), connectionRetryTimeout, TimeUnit.MILLISECONDS);
}
});
} catch (MqttException e) {
LOG.error("Connection error.", e);
}
}
What happens like this is that, when network connection is available I manage to connect automatically, but second thread is created which continues to retry to connect to broker. Does anyone already implemented this, or do you have any other suggestions?
The best way would be implementing a callback (asynchronous event based) that informs you as soon as teh network is available again
interface INetworkCallback{
void onNetworkStateChange(boolean newState);
}
and somewhere implement the interface
Related
I am creating a project with socket.io. It works really fine as long as there is just one fragment. However as I add more fragments in main activity, it starts creating multiple connections, which i think is not a good idea.
At first I connected to socket.io directly from fragments but that was creating one connection for each fragment. So I created a connection in Application class and used that in fragments which instantly solved multiple connection problem. But now a new problem has occurred.
In case of internet disconnection and reconnection, fragment doesn't get reestablished connection from Application class. I have been trying for over a week but no solution. strange thing is, i searched on internet and stackoverflow but not a single such question is ever asked.
here is connection code in Application class
synchronized public Socket getSocket() {
if (mSocket == null) {
try {
IO.Options opts = new IO.Options();
opts.reconnection = true;
opts.reconnectionDelay = 1000;
mSocket = IO.socket("http://ddbharti.in", opts);
mSocket.on(Socket.EVENT_CONNECT, new Emitter.Listener() {
#Override
public void call(Object... args) {
Log.d(TAG, "EVENT_CONNECT");
}
}).on(Socket.EVENT_DISCONNECT, new Emitter.Listener() {
#Override
public void call(Object... args) {
Log.d(TAG, "EVENT_DISCONNECT");
}
}).on(Socket.EVENT_ERROR, new Emitter.Listener() {
#Override
public void call(Object... args) {
Log.d(TAG, "error");
}
});
mSocket.connect();
} catch (URISyntaxException e) {
e.printStackTrace();
}
}
return mSocket;
}
and this is how each fragment is connecting
socket = application.getSocket();
socket.emit("tag", tag);
If internet is working fine, this setup works flawlessly, loads in 300 milliseconds. However as i disconnect/reconnect internet or I keep internet disconnected and start the app and then connect to internet. Connection in Application class connects quickly, but due to some reason connection in current fragment just doesn't get it.
If i switch fragments then it starts listening to connection from Application class again.
So am i missing something here? How can i force fragment to get connection from application class again in case of reconnection without reloading whole fragment?
Any help is greatly appreciated.
So i created an event listner to listen to socket connection status and show ui accordingly. Just one connect with event listner was all that was needed.
I am currently trying to publish a command to a specific topic in the IBM IoT Foundation MQTT Broker using a Java web application. My application is already able to listen to device events and act on them, however publishing commands to the device is a problem. I know for sure that my device is listening to the proper topic for commands, so what could be the problem? More specifically, here is the command I call to publish to the topic (from my Java app):
publish("iot-2/cmd/" + MQTTUtil.getDefaultCmdId() + "/fmt/json", rawJSONCommand, false, 0);
System.out.println("Finished sending command!");
Where the "publish" method is defined as follows:
public void publish(String topic, String message, boolean retained, int qos) { // check if client is connected
if (isMqttConnected())
{
// create a new MqttMessage from the message string
MqttMessage mqttMsg = new MqttMessage(message.getBytes());
// set retained flag
mqttMsg.setRetained(retained);
// set quality of service
mqttMsg.setQos(qos);
try {
System.out.println("About to send!");
client.publish(topic, mqttMsg);
System.out.println("Finished sending!"); }
catch (MqttPersistenceException e)
{ e.printStackTrace(); }
catch (MqttException e)
{ e.printStackTrace(); } }
else {
System.out.println("Connection lost!"); connectionLost(null);
} }
All that happens is that I enter the method, I get "About to send!" printed on my console as the code specifies, and then the actual 'client.publish(topic, mqttMsg)' call blocks my program indefinitely.. Eventually, after blocking for a while, I get the following error:
org.eclipse.paho.client.mqttv3.internal.ClientState checkForActivity SEVERE: a:2uwqwc:<MY_APP_NAME>: Timed out as no write activity, keepAlive=60,000 lastOutboundActivity=1,452,646,209,624 lastInboundActivity=1,452,646,149,303 time=1,452,646,329,628 lastPing=0
Thanks for the help!
If you are publishing from an application, are you specifying the device type and device id?
myAppClient.publishCommand(deviceType, deviceId, "stop", data);
Refer to section in documentation about publishing commands to connected devices.
https://docs.internetofthings.ibmcloud.com/java/java_cli_app.html
I'm trying to figure out how to send data between sockets in Java (this is part of a bigger project and I'll get back and answer my previous two questions related to that once I can resolve this..). I would like to connect a client and a server socket asynchronously in Java, and then send messages between them, and get a callback, say, when I have sent a message from the client to the server.
I think I have managed to get the set-up working. Here is my code:
private AsynchronousServerSocketChannel socListener;
private AsycnchrnonousSocketChannel socClient;
//This is the GUI callback for the button that initiates the socket server
private void button_StartSocketServerActionPerformed(ava.awt.event.ActionEvent evt)
{
try{
InetAddress ipLocal= InetAddress.getLocalHost();
InetSocketAddress ipSocket=new InetSocketAddress(ipLocal,8221);
m_socListener= AsynchronousServerSocketChannel.open().bind(ipSocket);
m_socListener.accept(null, new CompletionHandler<AsynchronousSocketChannel,Void>()
{
#Override
public void completed(AsynchronousSocketChannel ch, Void att)
{
// accept the next connection
m_socListener.accept(null, this);
// handle this connection
}
#Override
public void failed(Throwable exc, Void att) { }
}
);
}
catch (Exception e){
}
}
//This is the GUI callback for the button that initiates the client socket
private void button_StartClientSocketActionPerformed(java.awt.event.ActionEvent evt)
{
try
{
socClient=AsynchronousSocketChannel.open();
InetAddress ipLocal= InetAddress.getLocalHost();
InetSocketAddress ipSocket=new InetSocketAddress(ipLocal,8221);
socClient.connect(ipSocket, null, new CompletionHandler<Void,Void>()
{
#Override
public void completed(Void att1, Void att2)
{
// handle this connection
}
#Override
public void failed(Throwable exc, Void att) {}
}
);
}
catch (Exception e){
}
}
I'm including the server and the client in the same file for simplicity of testing.
So supposing the connection is successfully established, and I have a process on a timer (say) that was writing data to the server socket, I'd like to have the client socket 'listen' for this new data being sent from the server and then generate a callback when a write occurs (without doing something like periodically checking via a timer and a while loop to check that whether new data has been added). This is accomplishable in C# and a nice tutorial is available at:
http://www.developerfusion.com/article/3918/socket-programming-in-c-part-1/2/
Any tips on how to do this would be greatly appreciated. Thanks!
Chris
You could use RMI to accomplish that, the documentation can be found there:
http://www.oracle.com/technetwork/java/javase/tech/index-jsp-136424.html
With this, your server could notify your client as much as you need.
I'm digging a bug in my netty program:I used a heartbeat handler between the server and client,when client system rebooting,the heartbeat handler in server side will be aware of timeout and then close the Channel,but sometimes the listener registered in Channel's CloseFuture never be notified,that's weird.
After digging netty 3.5.7 source code,I figure out that the only way a Channel's CloseFuture be notified is through AbstractChannel.setClosed();May be this method not be executed when Channel is closed,see below:
NioServerSocketPipelineSink:
private static void close(NioServerSocketChannel channel, ChannelFuture future) {
boolean bound = channel.isBound();
try {
if (channel.socket.isOpen()) {
channel.socket.close();
Selector selector = channel.selector;
if (selector != null) {
selector.wakeup();
}
}
// Make sure the boss thread is not running so that that the future
// is notified after a new connection cannot be accepted anymore.
// See NETTY-256 for more information.
channel.shutdownLock.lock();
try {
if (channel.setClosed()) {
future.setSuccess();
if (bound) {
fireChannelUnbound(channel);
}
fireChannelClosed(channel);
} else {
future.setSuccess();
}
} finally {
channel.shutdownLock.unlock();
}
} catch (Throwable t) {
future.setFailure(t);
fireExceptionCaught(channel, t);
}
}
in some platform channel.socket.close() may throw IOException,that means channel.setClosed() may never executed,so the listener registered in CloseFuture may not be notified.
Here is my question:Do you ever encounter this problem? Is the analysis right?
I figure out it's my heartbeat handler cause the problem:never timeout,so never close the channel,below is running in a timer :
if ((now - lastReadTime > heartbeatTimeout)
&& (now - lastWriteTime > heartbeatTimeout)) {
getChannel().close();
stopHeartbeatTimer();
}
where lastReadTime and lastWriteTime are updated like below:
public void writeComplete(ChannelHandlerContext ctx, WriteCompletionEvent e)
throws Exception {
lastWriteTime = System.currentTimeMillis();
super.writeComplete(ctx, e);
}
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
throws Exception {
lastReadTime = System.currentTimeMillis();
super.messageReceived(ctx, e);
}
Remote client is Windows xp,current server is Linux,both jdk1.6.
I think the writeComplete still invoked internally after remote client's system is rebooting,although messageReceived not invoked,no IOExceptoin is thrown during this period.
I will redesign the heartbeat handler,attaching a timestamp and a HEART_BEAT flag in heartbeat packet,when the peer side received the packet,send back the packet with the same timestamp and a ACK_HEART_BEAT flag,when the current side received this ack packet,use this timestamp to update lastWriteTime.
I'm using a variation of the example at http://svn.apache.org/repos/asf/activemq/trunk/assembly/src/release/example/src/StompExample.java to receive message from a queue. What I'm trying to do is to keep listening to a queue and perform some action upon reception of a new message. The problem is that I couldn't find a way to register a listener to any of the related objects. I've tried something like:
public static void main(String args[]) throws Exception {
StompConnection connection = null;
try {
connection = new StompConnection();
connection.open("localhost", 61613);
connection.connect("admin", "activemq");
connection.subscribe("/queue/worker", Subscribe.AckModeValues.AUTO);
while (true) {
StompFrame message = connection.receive();
System.out.println(message.getBody());
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (connection != null) {
connection.disconnect();
}
}
}
but this doesn't work as a time out occurs after a few seconds (java.net.SocketTimeoutException: Read timed out). Is there anything I can do to indefinitely listen to this queue?
ActiveMQ's StompConnection class is a relatively primitive STOMP client. Its not capable of async callbacks on Message or for indefinite waits. You can pass a timeout to receive but depending on whether you are using STOMP v1.1 it could still timeout early if a heart-beat isn't received in time. You can of course always catch the timeout exception and try again.
For STOMP via Java you're better off using StompJMS or the like which behaves like a real JMS client and allows for async Message receipt.
#Tim Bish: I tried StompJMS, but couldn't find any example that I could use (maybe you can provide a link). I 'fixed' the problem by setting the timeout to 0 which seems to be blocking.
even i was facing the same issue.. you can fix this by adding time out to your receive() method.
Declare a long type variable.
long waitTimeOut = 5000; //this is 5 seconds
now modify your receive function like below.
StompFrame message = connection.receive(waitTimeOut);
This will definitely work.