We were trying to establish communication between verticles using event bus. We tried the simplest ping-pong communication example -
public class Sender extends AbstractVerticle {
public static void main(String[] args) {
Vertx.clusteredVertx(new VertxOptions(),res->{
res.result().deployVerticle(new Sender());
});
}
#Override
public void start() throws Exception {
EventBus eb = vertx.eventBus();
vertx.setPeriodic(1000, v -> {
eb.send("ping-address", "ping!", reply -> {
if (reply.succeeded()) {
System.out.println("Received reply: " + reply.result().body());
} else {
System.out.println("No reply");
}
});
});
}
}
Similarly we wrote the wrote the receiver. See the code.
Communication is successful if both the sender and receiver are run on the same machine. But when they are run different machines communication fails.
Also this does not seems to be the issue with Hazelcast Cluster manager (which we used) because hazelcast correctly discovers the other peer on both machine (this is evident from the console logs of hazelcast).
Members [2] {
Member [192.168.43.12]:5701
Member [192.168.43.84]:5701 this
}
Also firewall has not been enabled on both machines, and we were able to establish communication between the same machines using only hazelcast(without using vertx), and it worked perfectly (for example this).
So probably the issue is with vert-x.
Did you try setting setClustered(true) on VertxOptions? I was testing this example code and it works fine for me:
public static void main(String[] args) {
VertxOptions op = new VertxOptions();
op.setClustered(true);
Vertx.clusteredVertx(op, e -> {
if (e.succeeded()) {
HelloWorldVerticle hwv = new HelloWorldVerticle();
e.result().deployVerticle(hwv);
} else {
e.cause().printStackTrace();
}
});
}
Hazelcat communication is different from Vert.x communication.
From the documentation
"Cluster managers do not handle the event bus inter-node transport,
this is done directly by Vert.x with TCP connections."
When deploying, you can set the event bus to be in clustered mode.
From this on the documentation,
The event bus doesn’t just exist in a single Vert.x instance. By
clustering different Vert.x instances together on your network they
can form a single, distributed event bus.
With respect to clustering the event bus, the documentation says
The EventBusOptions also lets you specify whether or not the event
bus is clustered, the port and host.
When used in containers, you can also configure the public host and
port:
Code snippet is
VertxOptions options = new VertxOptions()
.setEventBusOptions(new EventBusOptions()
.setClusterPublicHost("whatever")
.setClusterPublicPort(1234)
);
Vertx.clusteredVertx(options, res -> {
// check if deployment was successful.
Other useful link is this
Related
Is it possible to change the url from Java class that is not a controller?
I've written a game of Go working as Client and Server applications (both written in Java, using Sockets to connect and exchange information in the shape of serialized messages). I run Server, two Clients, they connect and you can play. The client runs one javafx thread and one connecting thread that sends and listens for messages from Server as shown below. The server runs two threads that listen for messages from clients (decides turns internally), so you can surrender at any given time during the game. If it's not your turn moves and passes are ignored.
private void processCommands() throws ClassNotFoundException, IOException {
while (inputStream != null) {
if(!keepRunning) {
socket.close();
break;
}
ServerMessage serverMessage;
serverMessage = (ServerMessage) this.inputStream.readObject();
Platform.runLater(new Runnable() {
#Override
public void run() {
getServerMessage(serverMessage);
}
});
if(serverMessage instanceof EndGame)
keepRunning = false;
}
}
Now, with javafx I just call Platform.runLater and javafx thread receives a message and acts according to it (for example, for Move it puts a piece of white or black color on the board).
I want to try to change Client into webapp and I decided to use SpringMVC(used it before). Can I change view or url from the client connection class? Or is there a better way to do this? Or maybe send message to controller somehow?
Good morning,
in java.sun version of http servers we used to do this for creating contexts and different handlers :
server = HttpServer.create(new InetSocketAddress(PORT), 0);
server.createContext("/##getPersonalImage", new PersonalImageHandler());
server.createContext("/##getProfile", new ProfileGetter());
and then you could reach it by typing
127.0.0.1:15000/##getProfile
but in the netty i think i have searched every thing in examples etc , but havent seen creating contexts like this , is this some sort of depcerated method or what ?
could you please help me to achieve this sort of context in the netty too ? thanks in advance
Netty works in this fashion.
You have the server and/or client you must setup and when you set the server up you can add handlers by adding a ChannelInitializer. You can also add or remove on the fly, but this is not always recommended as it can be costly.
When you need to pass data to or from that is not network related or related to the network data you read you can take several approaches, such as extending the handlers and adding some sort of field where you can access or put data or use ChannelAttributes.
Their tutorials and examples definitely are helpful when building out. I will comment on their example and explain and hope that is helpful.
From their User Guide
Channels
Client Code
package io.netty.example.time;
public class TimeClient {
public static void main(String[] args) throws Exception {
String host = args[0];
int port = Integer.parseInt(args[1]);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(workerGroup);
b.channel(NioSocketChannel.class);
b.option(ChannelOption.SO_KEEPALIVE, true);
b.handler(new ChannelInitializer<SocketChannel>() { //** This is the ChannelInitializer - The Channel is the nexus basically to communications, you add handlers to the channel in the order of how data is handled
#Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new TimeClientHandler()); //** Here we are adding TimeClient Handler to the SocketChannel seen below, there are many ways to add handlers
}
});
// Start the client.
ChannelFuture f = b.connect(host, port).sync(); // (5)
// Wait until the connection is closed.
f.channel().closeFuture().sync();
} finally {
workerGroup.shutdownGracefully();
}
}
}
Handler Code
package io.netty.example.time;
import java.util.Date;
public class TimeClientHandler extends ChannelInboundHandlerAdapter {
#Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
ByteBuf m = (ByteBuf) msg; // Here we are getting the message
try {
long currentTimeMillis = (m.readUnsignedInt() - 2208988800L) * 1000L; //** We will always have to write the logic unless there is already a netty handler for it, but even then you may or probably will have to implement business logic handler specific to your application(s)
System.out.println(new Date(currentTimeMillis));
ctx.close(); //** you can close a connection on a channel or a ChannelHandlerContext
} finally {
m.release(); //** Here you have to release the buffer
}
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
So if you want to be able to reach out, when you construct the handler you can add your own fields. For the attributes method see ChannelHandler for examples ChannelHandler
EDIT: Will yes there is some Netty handlers for IP specific filtering, but I am not sure about it specifically. I am not sure what your trying to do as I do not know the other library you mentioned. To give you an Idea of how I use Netty may help you. I have a MMO style game, when a client connects its over TCP w/SSL when they connect though in the handler I have a Session class i create and tracks all there information. Then I prompt the client through my own network protocol to open another connection to the server using TCP w/o SSL. I add that to their Session, Then i negotiate if they can receive UDP and if so I build out a specific UDP handler for them and attach it to the Session. Each Session has its own Instance of the handlers in the Handler that allows me to read and write from one channel to another and or handle that person. Each session also references each of the handlers, channel and connection data. I also have a file server build on http and a post server built in netty, the client implements native Java, hence i used a web-server to not have initial dependencies.
To convince some people to switch from old school tech, I need to build a chat demo application that manages more than 10K concurrent connections using Java (like Node.Js stuff).
I have tested Netty 5.0 which is awesome but requires lot of work to be done; on the other hand Jetty 9.3 is great but is slow compared to other competitors.
After some search I found the Vert.x 3 toolkit which is based on Netty with a plethora of great tools (no need to reinvent the wheel), I have seen the examples in git and I was able to build a websocket server, etc.
public void start() throws Exception {
vertx.createHttpServer().websocketHandler(new Handler<ServerWebSocket>() {
#Override
public void handle(ServerWebSocket e) {
// business stuff in the old style not yet lambda
}
}).listen(port);
}
Being new to the Vert.x world, I could not figure out how to manage connected users using it, normally the old fashion way is to use something like:
HashMap<UUID,ServerWebSocket> connectedUsers;
When a connection is established I check if it exists; if not I add it as a new entry and do some functions to send, broadcast, retrieve through the collection and so on.
My question is does Vert.x 3 have something to deal with connections to track them and remove those who left (ping pong), broadcast, etc. or should I implement them from scratch using cookies, session, ....)
I could not find any real example using Vert.x 3.
Basically, the scope of the websocketHandler represents a connection. In your example this is your anonymous class. I created a little websocket chat example where I use the Vert.x event bus to distribute the messages to all the clients.
In the start method of the server we handle the websocket connections. You can implement the closeHandler to monitor client disconnection. There are also handlers for exceptions, ping-pong, etc. You can identify a specific connection by using the textHandlerID, but you have also access to the remote address.
public void start() throws Exception {
vertx.createHttpServer().websocketHandler(handler -> {
System.out.println("client connected: "+handler.textHandlerID());
vertx.eventBus().consumer(CHAT_CHANNEL, message -> {
handler.writeTextMessage((String)message.body());
});
handler.textMessageHandler(message -> {
vertx.eventBus().publish(CHAT_CHANNEL,message);
});
handler.closeHandler(message ->{
System.out.println("client disconnected "+handler.textHandlerID());
});
}).listen(8080);
}
The client example is also written in Java. It just prints all the received messages on the websocket connection to the console. After connection it sends a message.
public void start() throws Exception {
HttpClient client = vertx.createHttpClient();
client.websocket(8080, "localhost", "", websocket -> {
websocket.handler(data -> System.out.println(data.toString("ISO-8859-1")));
websocket.writeTextMessage(NAME+ ":hello from client");
});
}
I'm building a POC with Netty 4, just a basic client/server setup; my question is how to effectively share state across threads within the server process itself, let me explain...
Server
The server is nothing fancy; standard logic for accepting remote connections using boss and workers event loop groups (code not shown).
Where it gets interesting
The server supports pluggable modules that provide metrics and group management services. The modules run autonomously as child threads, periodically generating information important for the server to function properly; this is where I'm unsure what to do; how to get info produced from the thread modules to the server process in a "netty" way.
Naive Approach
Local VM Channel
Looking at example LocalEcho, it appears LocalChannel and LocalServerChannel provides VM (in-memory) communication, though I was expecting such channels to be easier to set up, but here goes:
//in-memory server
EventLoopGroup serverGroup = new DefaultEventLoopGroup();
ServerBootstrap svm = new ServerBootstrap();
svm.group(serverGroup)
.channel(LocalServerChannel.class)
.handler(new ChannelInitializer<LocalServerChannel>() {
#Override
public void initChannel(LocalServerChannel ch) throws Exception {
ch.pipeline().addLast(new LoggingHandler(LogLevel.INFO))
}
})
.childHandler(new ChannelInitializer<LocalChannel>() {
#Override
public void initChannel(LocalChannel ch) throws Exception {
ch.pipeline().addLast( EventsFromModule_Handler());
}
});
//start server vm
svm.bind(addr).sync();
//in-memory client
EventLoopGroup clientGroup = new NioEventLoopGroup();
Bootstrap cvm = new Bootstrap();
cvm.group(clientGroup)
.channel(LocalChannel.class)
.handler(new ChannelInitializer<LocalChannel>() {
#Override
public void initChannel(LocalChannel ch) throws Exception {
ch.pipeline().addLast(
new DefaultModuleHandler());
}
});
Connect Modules
Here's where I create and fork the modules; first I get a channel from the client vm, passing it to the module..
Channel mch = cvm.connect(addr).sync().channel();
ModuleFactory.fork(
new DiscoveryService( mch),
)
...now the module has a dedicated channel for generating events; such events will be handled by EventsFromModule_Handler(), bridging the gap between modules and the (server) process.
Question
I'm very new to netty, but is using LocalChannels in this context a valid approach?
Am I doing something entirely wrong?
I have some doubts regarding QoS=2 settings.
Mqtt publisher-subscriber am using Qos=2. Up to my knowledge by setting Qos=2 avoid duplication of message delivery among subscribers. In publisher i have set the Qos=2. I have two subscribers listening the same TOPIC. My code is running correctly but both subscribers getting the same message.
By setting Qos=2 Only one subscriber can get the message right?
How to solve this issue?
public class PubSync {
public static void main(String[] args) {
try {
MqttClient client = new MqttClient(TCPAddress,MqttClient.generateClientId());
MqttTopic topic = client.getTopic(MYTOPIC);
MqttMessage message = new MqttMessage(msg.getBytes());
message.setQos(2);
client.connect();
MqttDeliveryToken token = topic.publish(message);
token.waitForCompletion();
client.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
}
}
QOS 2 means the that each subscriber will only receive 1 copy of any given message.
This differs from QOS 1 where it is possible that a subscriber may receive multiple copies of the same message as the broker ensures that message is delivered.
The QOS levels do not change in any way how many subscribers will see a message.
Depending on the MQTT messaging provider you are using, you should be able to share a subscription to a topic across multiple subscribers so that only one subscriber receives each message. In this case the messaging provider handles distributing the workload evently across all the subscribers.
This is known as shared subscriptions and you can read more about how it works in IBM's MessageSight product here: http://pic.dhe.ibm.com/infocenter/ism/v1r0m0/topic/com.ibm.ism.doc/Overview/ov30010.html