I need to run a Server and Client in a application that trade string messages with each other(a chat), the code for this is working, part of it was provided by the teacher, but i'm stuck in one thing.
I want to run a class named "App", who creates a new Server and a new Client, but when i run both of then in the class, only one works.
package app;
import udp.Client;
import udp.Server;
public class App {
public static void main(String[] args) {
Server s = new Server();
s.Start();
Client c = new Client();
c.Start();
}
}
So to run the both of then, Server and Client, i need to comment out the client one, run the Server instance, then comment out the Server one, and run the Client instance, both classes initialize a thread.
How can i run both of then without that improvisation? I wanna hit "Run", and the code pops up the Server and the Client window.
I can provide the rest of the code if it's necessary.
new Thread(() ->
{
Server s = new Server();
s.Start();
}).start();
new Thread(() ->
{
Client c = new Client();
c.Start();
}).start();
Related
I am creating a simple micro service using vertx and when i start my server it only create one event thread when available is 12.
My code to start server is
public static void main(String[] args) {
Vertx vertx = Vertx.vertx();
int processorCounts = Runtime.getRuntime().availableProcessors();
DeploymentOptions options = new DeploymentOptions().setInstances(processorCounts);
vertx.deployVerticle( HttpRouter.class.getName(),options);
}
And my http router looks like this
#Override
public void start() throws Exception {
super.start();
Router router = Router.router(vertx);
router.get("/").handler(event -> {
event.response().end("Hello World");
});
vertx.createHttpServer().requestHandler(router::accept).listen(8001);
}
What is your process for testing? I assume you opened a browser and hit refresh on the same page. Then yes, the same verticle instance will handle the requests. The reason is Vert.x load balances connections among verticles instances, not requests.
Open a different browser and you should see different event loop names.
I want to create a communication system with two clients and a server in Netty nio. More specifically, firstly, I want when two clients are connected with the server to send a message from the server and after that to be able to exchnage data between the two clients. I am using the code provided from this example. My modifications in the code can be found here: link
It seems that the channelRead in the serverHandler works when the first client is connceted so it always return 1 but when a second client is connected does not change to 2. How can I check properly from the server when both clients are connected to the server? How can I read this value dynamically from my main function of the Client? Then which is the best way to let both clients communicate?
EDIT1: Apparently it seems that the client service is running and close directly so every time that I am running a new NettyClient is connected but the connection is closed after that. So the counter is always chnages from zero to one. As I was advised in the below comments I tested it using telnet in the same port and the counter seems to increasing normally, however, with the NettyClient service no.
EDIT2: It seems that the issue I got was from future.addListener(ChannelFutureListener.CLOSE); which was in channelRead in the ProcessingHandler class. When I commented it that out it seems that the code works. However, am not sure what are the consequences of commented that out. Moreover, I want from my main function of the client to check when the return message is specific two. How, could I create a method that waits for a specific message from server and meanwhile it blocks the main functionality.
static EventLoopGroup workerGroup = new NioEventLoopGroup();
static Promise<Object> promise = workerGroup.next().newPromise();
public static void callClient() throws Exception {
String host = "localhost";
int port = 8080;
try {
Bootstrap b = new Bootstrap();
b.group(workerGroup);
b.channel(NioSocketChannel.class);
b.option(ChannelOption.SO_KEEPALIVE, true);
b.handler(new ChannelInitializer<SocketChannel>() {
#Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new RequestDataEncoder(), new ResponseDataDecoder(), new ClientHandler(promise));
}
});
ChannelFuture f = b.connect(host, port).sync();
} finally {
//workerGroup.shutdownGracefully();
}
}
I want inside the main function to call the method and return the result and when it is 2 to continue with the main functionality. However, I cannot call callClient inside the while since it will run multiple times the same client.
callBack();
while (true) {
Object msg = promise.get();
System.out.println("Case1: the connected clients is not two");
int ret = Integer.parseInt(msg.toString());
if (ret == 2){
break;
}
}
System.out.println("Case2: the connected clients is two");
// proceed with the main functionality
How can I update the promise variable for the first client. When I run two clients, for the first client I always received the message :
Case1: the connected clients is not two
seems that the promise is not updated normally, while for the second client I always received the:
Case2: the connected clients is two
If my memory is correct, ChannelHandlerContext is one per channel and it can have multiple ChannelHandlers in it's pipeline. Your channels variable is an instance variable of your handler class. And you create a new ProcessingHandler instance for each connection. Thus each will have one and only one connection in channels variable once initialized - the one it was created for.
See new ProcessingHandler() in initChannel function in the server code (NettyServer.java).
You can either make channels variable static so that it is shared between ProcessingHandler instances. Or you can create a single ProcessingHandler instance elsewhere (e.g. as a local variable in the run() function) and then pass that instance to addLast call instead of new ProcessingHandler().
Why the size of ChannelGroup channels is always one. Even if I connect
more clients?
Because child ChannelInitializer is called for every new Channel (client). There you are creating new instance of ProcessingHandler, so every channel see its own instance of ChannelGroup.
Solution 1 - Channel Attribute
Use Attribute and associate it with Channel.
Create attribute somewhere (let's say inside Constants class):
public static final AttributeKey<ChannelGroup> CH_GRP_ATTR =
AttributeKey.valueOf(SomeClass.class.getName());
Now, create ChannelGroup which will be used by all instances of ProcessingHandler:
final ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
Update your child ChannelInitializer in NettyServer :
#Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(
new RequestDecoder(),
new ResponseDataEncoder(),
new ProcessingHandler());
ch.attr(Constants.CH_GRP_ATTR).set(channels);
}
Now you can access instance of ChannelGroup inside your handlers like this:
#Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
final ChannelGroup channels = ctx.channel().attr(Constants.CH_GRP_ATTR).get();
channels.add(ctx.channel());
This will work, because every time new client connects, ChannelInitializer will be called with same reference to ChannelGroup.
Solution 2 - static field
If you declare ChannelGroup as static, all class instances will see same ChannelGroup instance:
private static final ChannelGroup channels =
new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
Solution 3 - propagate shared instance
Introduce parameter into constructor of ProcessingHandler:
private final ChannelGroup channels;
public ProcessingHandler(ChannelGroup chg) {
this.channels = chg;
}
Now, inside your NettyServer class create instance of ChannelGroup and propagate it to ProcessingHandler constructor:
final ChannelGroup channels = new
DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
#Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(
new RequestDecoder(),
new ResponseDataEncoder(),
new ProcessingHandler(channels)); // <- here
}
Personally, I would choose first solution, because
It clearly associate ChannelGroup with Channel context
You can access same ChannelGroup in other handlers
You can have multiple instances of server (running on different port, within same JVM)
If I run this server program I got an above error. How should I clear this?
public class server {
public static void main(String args[]){ try {
System.out.println("Attempting to start XML-RPC Server...");
WebServer server = new WebServer(80);
(server).addHandler("sample", new server());
server.start();
System.out.println("Started successfully.");
System.out.println("Accepting requests. (Halt program to stop.)");
} catch (Exception exception){
System.err.println("server: " + exception);
}
}
}
What the error basically means is that the class WebServer doesnt have the relevant method in its definition.
What is the full qualified name of the WebServer class?
Assuming it is org.apache.xmlrpc.webserver.WebServer, you can look at the docs to see that it has no addHandler() method.
There is another problem with your code, you cannot call new on an object.
(server).addHandler("sample", new server());
Here server is an object not a class, and hence new server() is going cause you issues.
in xmlrpc-2.0.1 JAR addHandler(java.lang.String name, java.lang.Object target) method belongs to a class WebServer of xmlrpc and later on this method is removed. try using mentioned jar.
download from here http://archive.apache.org/dist/ws/xmlrpc/binaries
You can also find the API document at given link.
https://ws.apache.org/xmlrpc/xmlrpc2/apidocs/org/apache/xmlrpc/WebServer.html
I have a simple Client/Server Application. I try to access the arraylist from UI but get an empty arraylist in return. I have tried every possible solution on internet but none has worked in my case.
Server.java
import java.net.*;
import java.util.ArrayList;
import java.io.*;
public class Server {
public static ArrayList<MyThread> clients = new ArrayList<MyThread>();
public static void main(String args[]) throws IOException {
ServerSocket s = new ServerSocket(7777);
try {
while (true) {
Socket s1 = s.accept();
MyThread t = new MyThread(s1);
clients.add(t); // adds threads to an ArrayList
System.out.println(clients); // prints the ArrayList(It works and print all threads)
t.start(); //start the thread
}
} catch (SocketException e) {
System.out.println("Error: " + e);
}
}
}
This is a MouseClickeed method in my UI class where I want to access the ArrayList in Server Class
public void mouseClicked(MouseEvent arg0) {
try {
String s = textField.getText();
Client.ClientName = s; \\ gets the string entered and set it as Client Name
System.out.println(Server.clients); \\It's supposed to print Client ArrayList but instead it prints an empty List ([])
}
catch (NullPointerException e1) {
System.out.println("Error: " + e1);
}
}
});
It's look like you try to use objects from Server application in client application with UI.
Server and client app are two different processes.
Server.clients is initialized with values in your server app, and isn't initialized in your client app.
You're not just working with separate threads, you're working with different processes.
The Server process has it's own Server.class instance. The Client is launched in a different java process, it could use the same classes, but they will be different instances, even the static fields will be different in different processes.
If you need data from the Server in the Client, you need some sort of communication. You already have tcp/ip socket, so you could send the list via the socket.
Or you could use some distributed cache library if you want to use this pattern in a large application. E.g. hazelcast or Terracotta DSO
In one package I have two different classes Client.java and Server.java
I want to make this package jar, i mean executable.
First I want the Server class to run and after 2-3 seconds I want Client method to run. Is it possible?
Thank you
You have to leave only one main method and run your server and client in separate threads from it.
To do it, take a look at Runnable interface. Your server class and client class should implement it. Then you have to move the logic, used to start server and client to it's run() method.
class Server implements Runnable {
#Override
public void run() {
//your server starting logic here
}
}
class Client implements Runnable {
#Override
public void run() {
//your client starting logic here
}
}
After that, you can modify your main method, to start server and client, like:
public static void main(String args[]) throws InterruptedException {
Server server = new Server();
Client client = new Client();
Thread tServer = new Thread(server);
tServer.start();
//here you can wait some time to Server started
Thread tClient = new Thread(client);
tClient.start();
}