Java Mqtt Client disconnects after one message received by the callback - java

in my code, there are four classes: mainProgram, Coordinator class, Client Class and Callback Class.
The mainProgram, which contains the main method of the program, creates an instance of the Coordinator Class and calls its start() method.
The later creates two instances of the Client Class, a publisher and a subscriber, connects both of them and subscribes one of the instances, the subscriber, to multiple topics.
The Client Class contains everything what has to do with mqtt and concerning the Callback for the subscribe-method, I've created an own class for this, the Callback Class which receives in the messageArrived method the incoming mqtt messages.
This is the code of the main:
public class mainProgram throws MqttException {
public static void main(String[] args) {
Coordinator coordinator=new Coordinator();
coordinator.start();
}}
this is the code of the Coordinator class:
public class Coordinator {
Client publisher;
Client subscriber;
public Coordinator() {
// TODO Auto-generated constructor stub
}
public void start() throws MqttException {
Client publisher=new Client("publisher","tcp://192.168.0.10",0);
publisher.connect();
Client subscriber=new Client("subscriber","tcp://192.168.0.10",0);
subscriber.connect();
subscriber.subscribeToTopic(new String [] {"home/Sensor2","home/Sensor3"});
}
public void getMessage(String message) throws MqttPersistenceException, MqttException {
publisher.publish("home/Sensor4", message);
}}
This is the Client Class:
public class Client {
String brokerAddress;
String clientId;
int qos;
MqttClient mqttClient;
MqttConnectOptions conOpt;
MemoryPersistence persistence;
Coordinator coordinator;
public Client(String clientId, String brokerAddress, int qos) {
this.clientId=clientId;
this.brokerAddress=brokerAddress;
this.qos=qos;
this.setConOpt();
}
public void setConOpt() {
conOpt=new MqttConnectOptions();
conOpt.setKeepAliveInterval(30);
conOpt.setAutomaticReconnect(false);
}
public void connect() throws MqttException {
mqttClient=new MqttClient(brokerAddress,clientId,persistence);
this.mqttClient.setCallback(new Callback(this));
this.mqttClient.connect(this.conOpt);
while(this.mqttClient.isConnected()==false) {
System.out.println("Connecting");
System.out.println("...");
}
if(this.mqttClient.isConnected()==true){
System.out.println("Der Mqttclient "+this.mqttClient.getClientId()+" is now connected!");
}
}
public void subscribeToTopic(String [] topics) throws MqttException {
for(int i=0;i<topics.length;i++) {
this.mqttClient.subscribe(topics[i]);
}
}
public void publish(String topic, String message) throws MqttPersistenceException, MqttException {
MqttMessage mqttMessage=new MqttMessage(message.getBytes());
this.mqttClient.publish(topic, mqttMessage);
}
}
This is the Callback Class:
public class Callback implements MqttCallback{
Client client;
public Callback(Client client) {
// TODO Auto-generated constructor stub
this.client=client;
}
#Override
public void connectionLost(Throwable arg0) {
// TODO Auto-generated method stub
System.out.println("Connection to server's lost");
}
#Override
public void deliveryComplete(IMqttDeliveryToken arg0) {
// TODO Auto-generated method stub
System.out.println("Message's delivered");
}
#Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
String ingoingMsg=message.toString();
System.out.println("until here all's fine");
Coordinator coordinator=new Coordinator();
coordinator.getMessage(ingoingMsg);
}
}
The program starts, creates the clients and when I publish via MQTTfx a message to the above mentionned topics, in the console this shows up:
The program ends and the connection of the client "subscriber" ends when I call the method "coordinator.getMessage()" and nothing is published.
At the end, the program should behave like this:
create clients
connect clients
subscribe the subscriber client
Listen and if a message to the topic subscribed is published: Call the getMessage of the coordinator class to publish something
while and after publishing the listening to further messages should not end and the programm is "in a loop" until the user breaks it up.
I searched everywhere for a solution, but there are not quite the same problems that I have on the web.
Maybe you have some illuminating tips for me ...

Related

Java - How to simultaneously run two static and void functions with Executor Service

I'm trying to have my program be ready to send a message inputted by user and listen for an incoming message simultaneously.
I tried using Executor Service but it always gives an error that says the functions can't be static or void.
Because of this, I tried making my two functions (that I need to run simultaneously) non-static and return a String that I wouldn't do anything with. Unfortunately, I still get an error and I think it due to the fact that my functions use the static class variables declared prior.
Here's the error I get:
EchoClient.java:66: error: <anonymous EchoClient$1> is not abstract
and does not override abstract method call() in Callable
callables.add(new Callable() {
Here's me the code simplified and without the Executor Service:
class EchoClient
{
public static DatagramSocket socket; public static InetAddress receiver; public static int port;
public static void main( String args[] ) throws Exception
{
//Initialization of socket, receiver and port
while(true)
{
sendMessage();
receiveMessage();
}
}
public static void sendMessage() throws IOException
{
//Actions to send message
}
public static void receiveMessage() throws IOException
{
//Actions to receive message
}
}
The functions I want to run simultaneously are sendMessage() and receiveMessage(). Right now I'm using a while loop so the program can only send a message before waiting to receive one and vice versa.
I'm really not that familiar with Java, so I'm just hoping for a simple implementation of Executor Service.
Since you know that you will need 2 Threads you can use a FixedThreadPool:
Executor executor = Executors.newFixedThreadPool(numberOfThreads);
To execute a Task you just need to call the execute methode with your runnable as a parameter:
executor.execute(() -> {
while (true) {
try {
sendMessage();
} catch (IOException e) {
e.printStackTrace();
break;
}
}
});

messageArrived never called in mqtt paho client

I have a program running using mqtt paho version MqttConnectOptions.MQTT_VERSION_3_1_1 . I subscribe to topic "device/+/publish" and message from hardware is received at my program. Till yesterday it was running good, today I got an issue that code was not proceeding after the subscribe line. I changed my mqttclient object to MqttAsyncClient. and subscribe code as
mqttClient.subscribe("device/+/publish", 0 , new IMqttMessageListener() {
#Override
public void messageArrived(String topic, MqttMessage mqttMessage) throws Exception {
// TODO Auto-generated method stub
System.out.println(
"---------------------------------------------------------------------------------------------------");
processMessage(mqttMessage, collarTopic, identity);
}
});
messageArrived is also written in MqttCallbackExtended() like
mqttClient.setCallback(new MqttCallbackExtended() {
#Override
public void messageArrived(String topic, MqttMessage mqttMessage) throws Exception {
// TODO Auto-generated method stub
System.out.println(
"---------------------------------------------------------------------------------------------------");
processMessage(mqttMessage, collarTopic, identity);
}
But this is never called in my program. I can see the message received with same subscription in MQTTBox but not in my program.
Can anyone help?

Multiple ChannelInboundHandlerAdapter's in Netty pipleline

I'm quite new with netty, I want to create a TCP server which does a custom application layer handshaking when a connection is to be instantiated. After the handshaking I want to pass the messages (ByteBuf) to a queue so that they could be processed by some other threads.
My question is, can I have multiple ChannelInboundHandlerAdapter's in the channel pipeline? one for the application layer handshaking protocol and the other one for passing the message to the queue. Furthermore I want to know how the messages flow through the pipeline. If a message is received at one handler (or decoder/encoder) how is it passed to another handler.
Specifically, if I change the EchoServer from here and add another ChannelInboundHandlerAdapter, the echo server handler would stop receiving any messages.
ServerBootstrap b = new ServerBootstrap();
b.group(group)
.channel(NioServerSocketChannel.class)
.localAddress(new InetSocketAddress(port))
.childHandler(new ChannelInitializer<SocketChannel>() {
#Override
public void initChannel(SocketChannel ch)
throws Exception {
ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {
#Override
public void channelRead(ChannelHandlerContext ctx,
Object msg) {
}
});
ch.pipeline().addLast(
new EchoServerHandler());
}
});
My logic is: have 2 ChannelInboundHandlerAdapter's then do the handshaking with the first handler and discard packets if they do not match the handshaking criteria, and then pass the messages to a queue through the second ChannelInboundHandlerAdapter. Is my logic correct? If not how should it be?
Thank you very much.
ChannelInboundHandlerAdapter is an adapter class to the ChannelInBoundHandler interface. For beginning you can use SimpleChannelInboundHandler (or more complicated you can extend the adapter class writing your own handler that extends ChannelInboundHandlerAdapter ).
The SimpleCHannelInboundHandler releases the message automatically after channelRead() (and thereby passes it to the next handler in the ChannelPipeline).
For using the easier SimpleChannelInboundHandler see this thread Netty hello world example not working
So instead of this ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {}
you have to write a new class that extends SimpleChannelInboundHandler like
public class MyHandler extends SimpleChannelInboundHandler{
#Override
protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
try {
System.out.println(in.toString(io.netty.util.CharsetUtil.US_ASCII));
} finally {
in.release();
}
}
}
and invoke it like
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new MyHandler());
}
As said above the SimpleCHannelInboundHandler releases the message automatically after channelRead() (and thereby passes it to the next handler in the ChannelPipeline).
If you use ChannelInboundHandlerAdapter you have to implement the passing of the message/event to the next handler yourself
A handler has to invoke the event propagation methods in ChannelHandlerContext ctx to forward an event to its next handler. (in the SimpleChannelInboundHandler class this is implemented yet)
public class MyInboundHandler extends ChannelInboundHandlerAdapter {
#Override
public void channelActive(ChannelHandlerContext ctx) {
System.out.println("Connected!");
ctx.fireChannelActive();
}
}
See this http://netty.io/4.0/api/io/netty/channel/ChannelPipeline.html
I must remind that:
Only One SimpleChannelInboundHandler extention can be add to the pipeline chain.
Because SimpleChannelInboundHandler have a finally code block will release all the msg.
#Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
boolean release = true;
try {
if (acceptInboundMessage(msg)) {
#SuppressWarnings("unchecked")
I imsg = (I) msg;
channelRead0(ctx, imsg);
} else {
release = false;
ctx.fireChannelRead(msg);
}
} finally {
if (autoRelease && release) {
//release all handled messages,so the next handler won't be executed
ReferenceCountUtil.release(msg);**
}
}
}
Use ChannelInboundHandlerAdapter instead:
public class CustomizeChannelInboundHandler extends ChannelInboundHandlerAdapter {
#Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("do something you like!")
super.channelRead(ctx, msg);
}
}

Netty 4 Calls being blocked , Simple Telnet Server

I am trying to play around with netty api using Netty Telnet server to check if the true asynchronous behaviour could be observed or not.
Below are the three classes being used
TelnetServer.java
public class TelnetServer {
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new TelnetServerInitializer());
b.bind(8989).sync().channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
TelnetServerInitializer.java
public class TelnetServerInitializer extends ChannelInitializer<SocketChannel> {
private static final StringDecoder DECODER = new StringDecoder();
private static final StringEncoder ENCODER = new StringEncoder();
private static final TelnetServerHandler SERVER_HANDLER = new TelnetServerHandler();
final EventExecutorGroup executorGroup = new DefaultEventExecutorGroup(2);
public TelnetServerInitializer() {
}
#Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
// Add the text line codec combination first,
pipeline.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
// the encoder and decoder are static as these are sharable
pipeline.addLast(DECODER);
pipeline.addLast(ENCODER);
// and then business logic.
pipeline.addLast(executorGroup,"handler",SERVER_HANDLER);
}
}
TelnetServerHandler.java
/**
* Handles a server-side channel.
*/
#Sharable
public class TelnetServerHandler extends SimpleChannelInboundHandler<String> {
#Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
// Send greeting for a new connection.
ctx.write("Welcome to " + InetAddress.getLocalHost().getHostName() + "!\r\n");
ctx.write("It is " + new Date() + " now.\r\n");
ctx.flush();
ctx.channel().config().setAutoRead(true);
}
#Override
public void channelRead0(ChannelHandlerContext ctx, String request) throws Exception {
// Generate and write a response.
System.out.println("request = "+ request);
String response;
boolean close = false;
if (request.isEmpty()) {
response = "Please type something.\r\n";
} else if ("bye".equals(request.toLowerCase())) {
response = "Have a good day!\r\n";
close = true;
} else {
response = "Did you say '" + request + "'?\r\n";
}
// We do not need to write a ChannelBuffer here.
// We know the encoder inserted at TelnetPipelineFactory will do the conversion.
ChannelFuture future = ctx.write(response);
Thread.sleep(10000);
// Close the connection after sending 'Have a good day!'
// if the client has sent 'bye'.
if (close) {
future.addListener(ChannelFutureListener.CLOSE);
}
}
#Override
public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush();
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
Now when i connect through telnet client and send commands hello hello hello three times
the request doesn't reach channelRead until first response to channelRead is being done is there any way i can make it asynchronous completely as to receive three hello as soon as they are available on socket.
Netty uses 1 thread max for every incoming read per handler, meaning that the next call to channelRead will only be dispatched after the previous call has been completed. This is required to for correct working of most handlers, including the sending back of messages in the proper order. If the amount of computation is really complex, another solution is using a custom thread pool for the messages.
If the other operation is instead a other kind of connection, you should use that as a async connection too. You can only get asynchronous if every part does this correctly.

How could a Netty server send data to different clients?

I wanna make something like a simple chat.
Server have to add new clients in a list of clients, and when one client sends message to the server, server have to resend this message to the other clients.
I know, how to read message from client, but I don't know, how to send message from server to the client. And i don't sure where should be list of clients, but guess that in handler class.
Here is my main class which initializes the server class
package firstPackage;
public class main {
public static void main(String[] args) throws Exception
{
Server server = new Server(9050);
server.run();
}
}
Here is the Server class
package firstPackage;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.SocketChannel;
public class Server {
private int port;
public Server(int port)
{
this.port=port;
}
public void run() throws Exception
{
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try{
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup,workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
#Override
public void initChannel(SocketChannel ch) throws Exception{
ch.pipeline().addLast(new DiscardServerHandler());
}
})
.option(ChannelOption.SO_BACKLOG,128)
.childOption(ChannelOption.SO_KEEPALIVE, true);
ChannelFuture f = b.bind(port).sync();
f.channel().closeFuture().sync();
}
finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
}
And here the Handler class
package firstPackage;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.ReferenceCountUtil;
public class DiscardServerHandler extends ChannelInboundHandlerAdapter {
#Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf in = (ByteBuf) msg;
try {
while (in.isReadable()) {
System.out.print((char) in.readByte());
System.out.flush();
}
System.out.println();
ctx.writeAndFlush("hey"); // вот здесь я думал, что сообщение будет отправлятся клиенту, от которого я получил сообщение, но не отправляется
} finally {
ReferenceCountUtil.release(msg);
}
}
#Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("channel is active");
}
#Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
System.out.println("channel is invactive");
}
#Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
System.out.println("handler added");
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
Actually now I have not list of clients, because i even don't know what type of object this list must contain, in C# it's was Socket object, so what in Netty?
I'm betting this example should help you out (it's a YouTube video, so spare the comments about broken links please). In particular, it uses a ChannelGroup to solve the problem of which you ask. And, yes, it goes in the handler on the server side.
Edit:
Notice too that in the example the ChannelGroup is static. I might argue it would be better to not use a static member and inject a ChannelGroup into the handler from the server class, but the simplicity of the static member may be preferable if you just want to get something working quickly.

Categories

Resources