Basically I need to make a server that handles multiple devices sending/receiving information. I have to be able to send commands to the devices. The number of devices is about 40 for now but will increase to maybe 400 over time. The devises will always send information once every 40seconds-60seconds which is set on the device so it can vary, but may also send more information depending on other factors, such as a responses to commands sent to it. So I have read there is java NIO which I can use or what I have currently done is created a thread for each incoming connection. The sending is not a constant thing so it needs to happen on demand, based on users input on my jsp website. So this is where I am stuck. How do I accomplish the sending of commands from outside the program where the connection is.
This is what I currently have:
Main server class to handle connections and make threads.
try (ServerSocket serverSocket = new ServerSocket(portNumber)) {
while (listening) {
ServerThread r = new ServerThread(serverSocket.accept());
Thread thread = new Thread(r);
thread.setDaemon(true);
System.out.println(thread.getId() + "thread");
thread.start();
thread.join();
}
} catch (IOException e) {
System.err.println("Could not listen on port " + portNumber);
System.exit(-1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Then the ServerThread class:
public class ServerThread implements Runnable{
private Socket socket = null;
public AtomicBoolean isStopped=new AtomicBoolean(false);
public ServerThread(Socket socket) {
this.socket = socket;
}
public void run() {
while(!this.isStopped.get()){
try (
DataInputStream in = new DataInputStream(socket.getInputStream());
) {
ReceiveThread r = new ReceiveThread(in);
Thread thread = new Thread(r);
thread.setDaemon(true);
thread.start();
thread.join();
socket.close();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
Then the ReceiveThread handles the reading/decoding.
On demand infrequent communication is better handled via UDP maybe with re-transmission implementation if you need to make sure that data is received, alternatively you can use NIO channels to handle that.
Creating a Thread for every client if the communication is infrequent is wasteful and pointless.
Related
So my question goes here. Now if my Server has over 20 clients, it also has 20 threads and my desktop with an ryzen CPU goes to 100% at usage at 30 Threads. Now I'd like to handle a mass-amount of clients by one server, but the CPU is just getting over-used. My wise is very simple how I do it, but there must be a better way; because I saw many good java servers so far yet. I don't know what I do wrong though. In the following I share my code, how I do it in principle.
while(this.isRunning()) {
ServerSocket server = new ServerSocket(8081);
Socket s = server.accept();
new Thread(new WorkerRunnable(s)).start();
//now here if e.g. over 25 users connect there are 25 threads. CPU is at 100%. Is there a better way to handle this?
The worker runnable is identifing the clients. After that they will get into a chat-room. Its like a group chat for e.g.
Edit: Relevant parts of my very unfinished code which is still very WIP
private boolean state;
private ServerSocket socket;
#Override
public void run() {
while(this.isRunning()==true) {
try {
if(this.socket==null) this.socket = new ServerSocket(this.getPort());
Socket connection = this.socket.accept();
IntroductionSession session = new IntroductionSession(this, connection);
new Thread(session).start();
//register timeout task for 3 secs and handle it async
System.out.println(ManagementFactory.getThreadMXBean().getThreadCount());
//this.handleIncomingConnection(connection);
} catch(Exception e) {
e.printStackTrace();
//System.exit(1);
}
}
}
private class IntroductionSession implements Runnable {
private boolean alive = true;
private BaseServer server;
private Socket socket;
private boolean introduced = false;
public IntroductionSession(BaseServer server, Socket socket) {
this.server = server;
this.socket = socket;
}
private void interrupt() {
System.out.println("Not mroe alive");
this.alive = false;
}
private void killConnection() {
this.killConnection("no_reason");
}
private void killConnection(String reason) {
try {
if(this.from_client!=null) this.from_client.close();
if(this.to_client!=null) this.to_client.close();
this.socket.close();
switch(reason) {
case "didnt_introduce":
System.out.println("Kicked connection, cause it didn't introduce itself");
break;
case "unknown_type":
System.out.println("Kicked unknown connection-type.");
break;
case "no_reason":
default:
//ignore
break;
}
} catch (IOException e) {
switch(reason) {
case "didnt_introduce":
System.out.println("Error at kicking connection, which didn't introduce itself");
break;
case "unknown_type":
System.out.println("Error at kicking unknown connection-type.");
break;
case "no_reason":
default:
System.out.println("Error occured at kicking connection");
break;
}
e.printStackTrace();
}
}
private ObjectInputStream from_client;
private ObjectOutputStream to_client;
#Override
public void run() {
while(this.alive==true) {
try {
if(this.to_client==null) {
this.to_client = new ObjectOutputStream(this.socket.getOutputStream());
//this.to_client.flush();
}
if(this.from_client==null) this.from_client = new ObjectInputStream(this.socket.getInputStream());
//Time runs now, if socket is inactive its getting kicked
new Timer().schedule(new java.util.TimerTask() {
#Override
public void run() {
if(IntroductionSession.this.introduced==false) {
IntroductionSession.this.killConnection("didnt_introduce");
Thread.currentThread().interrupt();
IntroductionSession.this.interrupt();
}
}
}, 5000
);
Object obj = this.from_client.readObject();
while(obj!=null) {
if(obj instanceof IntroductionPacket) {
IntroductionPacket pk = (IntroductionPacket) obj;
introduced = true;
if(isCompatible(pk)==false) {
try {
this.to_client.writeObject(new DifferentVersionKickPacket(BaseServer.version));
this.to_client.close();
this.from_client.close();
IntroductionSession.this.socket.close();
System.out.println("Kicked socket, which uses another version.");
} catch(Exception e) {
Thread.currentThread().interrupt();
//ignore
System.out.println("Error at kicking incompatible socket.");
e.printStackTrace();
}
} else {
this.server.handleIncomingConnection(this.socket, this.from_client, this.to_client);
}
Thread.currentThread().interrupt();
}
}
} catch(StreamCorruptedException e) {
//unknown client-type = kick
this.killConnection("unknown_type");
} catch (IOException|ClassNotFoundException e) {
e.printStackTrace();
this.killConnection("no_reason");
}/* catch(SocketException e) {
}*/
}
Thread.currentThread().interrupt();
}
}
Extending class, which is an actual server:
#Override
public void handleIncomingConnection(Socket connection, ObjectInputStream from_client, ObjectOutputStream to_client) {
new AuthenticationSession(connection, from_client, to_client).run();
}
private class AuthenticationSession implements Runnable {
private Socket socket;
private ObjectInputStream from_client;
private ObjectOutputStream to_client;
public AuthenticationSession(Socket socket, ObjectInputStream from_client, ObjectOutputStream to_client) {
this.socket = socket;
this.to_client = to_client;
this.from_client = from_client;
}
//TODO: Implement app id for access tokens
#Override
public void run() {
try {
while(this.socket.isConnected()==true) {
/*ObjectOutputStream to_client = new ObjectOutputStream(socket.getOutputStream()); //maybe cause problems, do it later if it does
ObjectInputStream from_client = new ObjectInputStream(socket.getInputStream());*/
Object object = from_client.readObject();
while(object!=null) {
if(object instanceof RegisterPacket) {
RegisterPacket regPacket = (RegisterPacket) object;
System.out.println("Username:" + regPacket + ", password: " + regPacket.password + ", APP-ID: " + regPacket.appId);
} else {
System.out.println("IP " + this.socket.getInetAddress().getHostAddress() + ":" + this.socket.getPort() + " tried to send an unknown packet.");
this.socket.close();
}
}
}
}/* catch(EOFException eofe) {
//unexpected disconnect
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}*/
catch(Exception e) {
e.printStackTrace();
System.exit(1);
}
/*catch(Exception e) {
//e.printStackTrace();
Thread.currentThread().interrupt();
}*/
}
}
Please dont look at its very bad formatting and stuff I did in hope to fix it, the tasks dont die whyever though.
Generally, in production grade server code, we don't work with direct creation of socket and handling of requests. It's a nightmare to work with low level sockets, close connections and prevent leaks. Rather, we rely on production grade frameworks such as Java Spring Framework or Play Framework.
My question is, why aren't you using any server-side frameworks such as the ones I listed above?
If you're wondering how these frameworks handle thousands of concurrent requests, look into design patterns such as Thread Pool. These frameworks abstract away the complexities and handle the thread pool for you.
If the clients aren't expected to receive an immediate response, you could also look into introducing messaging queue such as Kafka. The server will pick the messages one by one from the queue and process them. However, bear in mind that this is asynchronous and may not meet your requirements.
If you're not just restricted to one server, you could look into deploying your server code to Azure or AWS VMSS (Virtual machine scale set). Based on CPU load rules you configure, the system will autoscale and dynamically manage resources for you.
I would suggest reading upon system design principles related to servers to reinforce your understanding.
Don't reinvent the wheel.
Since you are doing a Chat Application you need to think of doing a Single Threaded Event Loop.
You can Keep a Map of String (Client id) and Socket (Client socket).
Map<String, Socket> clientSockets;
You Server thread will accept new Client Sockets and will just put it in the above map. Then there will be another Thread which will do the Event Loop and whenever there is data in any of the Client Socket in InputStream it should send that data to all other Client Sockets (Group Chat). This should happen infinitely with a Sleep interval.
I am developing a program that has a chat feature and I am using sockets in it.
In my case, I want to handle each of the client in a different window chat(PLEASE SEE ATTACHED IMAGE).
As of now, when 1 client is connected, there is no problem. But when 2 clients are connected, the first client will be overridden by the 2nd one and he can't receive messages from server not unless I close the connection for the latest client connected(Server still receiving messages from all client although only 1 client can receive from server).
How am I gonna do this? I am using captain casa framework
I want to manage it like what did the image below do.
IMAGE HERE
Here is my code:
Server:
public void mainserver(){
Thread server = new Thread(new Runnable() {
#Override
public void run() {
try {
serverSocket = new ServerSocket(port);
System.out.println("Server Online... \nWaiting for Connections");
} catch (IOException e) {
e.printStackTrace();
}
while (accept){
try {
socket = serverSocket.accept();
System.out.println("New Connection Estasblished!!!");
chatHandler chat = new chatHandler(socket);
chat.start();
} catch (IOException e) {
System.out.println("server not terminate all connections");
System.exit(-1);
}
}
}
});
server.start();
}
public class chatHandler extends Thread{
Socket socket;
public chatHandler(Socket socket){
this.socket = socket;
}
public void run(){
try {
din = new DataInputStream(socket.getInputStream());
dout = new DataOutputStream(socket.getOutputStream());
dout.writeUTF("Hi! Thank you for reaching us! How may I help you!?");
while (!read.equals(".end")){
read = din.readUTF();
if (getServerArea()!=null){
setServerArea(getServerArea()+"\n"+read);
}else {
setServerArea(read);
}
}
System.out.println("end of chat server");
} catch (IOException e) {
e.printStackTrace();
}finally {
System.out.println("Exit");
try {
dout.close();
din.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public void serverSend(javax.faces.event.ActionEvent event) { // "Send" button
write = getServerField();
try {
dout.writeUTF(write);
dout.flush();
if (getServerArea()!=null){
setServerArea(getServerArea()+"\n"+write);
setServerField("");
}else {
setServerArea(write);
setServerField("");
}
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(write);
}
Client:
public void client(){
Thread client = new Thread(new Runnable() {
#Override
public void run() {
try {
socket = new Socket("localhost",port);
din = new DataInputStream(socket.getInputStream());
dout = new DataOutputStream(socket.getOutputStream());
while (!read.equals("bye")){
read = din.readUTF();
if (getClientArea()!=null){
setClientArea(getClientArea()+"\n"+read);
}else {
setClientArea(read);
}
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
din.close();
dout.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
});
client.start();
}
public void clientSend(javax.faces.event.ActionEvent event) {
write = getClientField();
try {
dout.writeUTF(write);
dout.flush();
if (getClientArea()!=null){
setClientArea(getClientArea()+"\n"+write);
setClientField("");
}else {
setClientArea(write);
setClientField("");
}
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(write);
}
I believe I understand the problem, and how to correct it.
You are using a unique thread (chatHandler) for each new connection.
This thread writes an automatic "Hello" upon connection, but thereafter is dedicated to reading messages (in the while loop you only read din) and updating the console accordingly. Since each thread is managing a reference to din, all incoming messages are OK.
However, it seems that writing back to a client (serverSend) is not in a thread; it is triggered by a button event. At this point, dout will be a reference to the most recent connection, and not a reference to the client intended to get the message. That is why the most recent client gets all future messages.
The correction is to choose the correct 'dout' for the intended client. When the server 'operator' chooses to write a message back (clicking the send button), somehow you need to obtain the correct 'dout' for that client.
One way to do this is to establish dout prior to creating the thread (using socket), and maintain a relationship between each client, and it's corresponding dout (i.e. in a Map).
If the problem is still not clear (that each client must have a unique reference to dout), please let me know and I will try to clarify.
i am creating a multiple-client/server app whenever any client disconnects from
my server it just hangs.
how can i set any condition that will tell me print some message whenever
any client disconnects from the server
here is my server code
class ServerThread implements Runnable {
public void run() {
Socket socket = null;
try {
System.out.println("server starting.......");
serverSocket = new ServerSocket(SERVERPORT);
} catch (IOException e) {
e.printStackTrace();
}
while (!Thread.currentThread().isInterrupted()) {
try {
System.out.println("Ready to accept.......");
socket = serverSocket.accept();
System.out.println(" client Connected with ip address =" +socket.getRemoteSocketAddress().toString());
CommunicationThread commThread = new CommunicationThread(socket);
new Thread(commThread).start();
} catch (IOException e) {
e.printStackTrace();
System.out.println("catch block");
}
}
}
}
class CommunicationThread implements Runnable {
private Socket clientSocket;
private BufferedReader input;
public CommunicationThread(Socket clientSocket) {
this.clientSocket = clientSocket;
try {
this.input = new BufferedReader(new InputStreamReader(this.clientSocket.getInputStream()));
} catch (IOException e) {
e.printStackTrace();
}
}
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
String read = input.readLine();
updateConversationHandler.post(new updateUIThread(read));
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
any help will be appreciated
It's not clear whether you mean disconnect because the conversation was over (ie: everything completed successfully) or the disconnect is because of some network problems (or the client canceled the request).
If it's the first case, then it's easy: the protocol you are using (your own, or http, or whatever) is in charge of defining how to determine that a conversation was over. If that situation arises, then you just close the socket.
If it's the second case, then you'd have to have an algorithm in place to determine whether or not the connection must be closed. For instance, by implementing a timeout, or a slow-read threshold. Take a look at the Socket's javadoc for instructions on how to set a timeout.
It's also worth noting that it's fine to create your own servers when you want to practice or learn something, but you'd be better off using an existing solution, like vert.x or a slimmed down version of Wildfly, for instance. The overhead of such servers is very low, nowadays, while still providing very robust networking capabilities.
guys! i wrote simple server client (udp) application. Now i am trying to make server that accepts many clients. As, i understood, i need to create functions, that accepts and handle clients, but i am confused about apps structure. Can u check if i have right skeleton for my app? Mayb u can give me some hint or example. All advice appreciated! :)
class MultiServer {
private DatagramSocket serversocket;
public MultiServer() {
try {
this.serversocket = new DatagramSocket(6789);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void start() throws IOException {
while(true) {
DatagramSocket serversock = serversocket.accept();
new Thread(new ClientHandler(serversock)).start();
}
}
public static void main(String[] args) {
Server1 server = new Server1();
try {
server.start();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class ClientHandler implements Runnable {
private final DatagramSocket clientsocket;
ClientHandler(DatagramSocket sock) {
this.clientsocket = sock;
}
#Override
public void run() {
//receive packet, send msg, get ip, get portnumber ?
}
}
}
So you want your server to be able to operate with multiple requests at the same time? Good, it's how most web-servers work. You have to understand the basic concepts of multi-threading and concurrency.
A simple server can only handle ONE thing at a time. What happens if another request is received while the server is dealing with something else? Nothing, so the application isn't very efficient and not scalable at all.
If you haven't used multiple threads in your applications yet and don't know much about concurrency, it's a great time to have a go, read the Oracle Concurrency Lesson, or find a tutorial online, there are plenty.
Now, once (or if) you know how threading works make sure you break down your functions as much as possible and see what functions can happen at the same time. An example of a Web Server that i can think of is this:
A separate thread to listen on the port for requests. Once a request is received, place it in the 'request pool' and queue it to be processed
A separate thread (or multiple threads/thread pool) that process the request
Your structure looks like you have both receive and process in the same Runnable. Anyway, this is just an idea, you'll have to see what's more applicable to your application. Also, have a look at the Concurrency tools that newer Java versions provide, Java 6 and 7 provide a lot of tools you can use that are very effective (but also quite hard to understand and use in my opinion).
Good luck!
You are looking for a Threadpooled Server. The way you started is good. Now you simply implement a Java execution Service to Handle the requests. The threadpool has a fixed of thread. It does take your requests and put those in a queue and if a request is done it takes the next request. So you normaly dont lose any requests.
Here is a small example i made:
public class PoolServer implements Runnable {
private static final int DEFAULT_PORT = 8080;
private static final String CONFIG = "config.xml";
protected ServerSocket serverSocket = null;
protected boolean isStopped = false;
protected Thread runningThread = null;
protected ExecutorService threadPool = Executors.newFixedThreadPool(100);
protected int serverPort;
public PoolServer() {
// getting the port from the XML
this.serverPort = getPortFromXML();
}
public void run() {
synchronized (this) {
this.runningThread = Thread.currentThread();
}
openServerSocket();
// accepting loop
while (!isStopped()) {
Socket clientSocket = null;
try {
// accept the client
clientSocket = this.serverSocket.accept();
clientSocket.setSoTimeout(2000);
} catch (IOException e) {
if (isStopped()) {
return;
}
throw new RuntimeException("Error accepting client connection",
e);
}
this.threadPool.execute(new ThreadHandler(clientSocket));
}
// loop end
// server stopped shut down the ThreadPool
this.threadPool.shutdown();
}
private synchronized boolean isStopped() {
return this.isStopped;
}
public synchronized void stop() {
this.isStopped = true;
try {
this.serverSocket.close();
} catch (IOException e) {
throw new RuntimeException("Error closing server", e);
}
}
private void openServerSocket() {
try {
this.serverSocket = new ServerSocket(this.serverPort);
} catch (IOException e) {
throw new RuntimeException("Cannot open port " + this.serverPort, e);
}
}
At this point this.threadPool.execute(new ThreadHandler(clientSocket)); i do execute the request if a thread is free. Else it get into the queue of the Threadpool.
You can even change it from a Fixed to some other Threadpools! Just take a look at the Executors and take what you need. Executors
Hope this helps!
Im creating a server client program where client sends certain information to the server and get according response from the server.
For continuously listening from multiple clients I have a thread in server which continuously listens client request. whenever a request is received I start another thread and send that socket to run and start listening for other clients request.
here is the code for continuously listening
while(true){
//serverListener is a ServerSocket object
clientSocket = serverListener.accept();//Waiting for any client request
//New thread started when request is received from any client
Thread thread =new Thread(new serverThread(clientSocket), "ClientThread");
thread.start();
}
Now my problem is that how can i stop the server. I know one alternative of using a boo lean variable in while loop and then changing the value, but the problem is when where thread is in waiting to get any connection at that time changing value of the boolean variable will also not stop the server.
Is there any way to solve this problem.
Typically the serverListener (which I assume is actually a ServerSocket or something) is closed by another thread. This will generate a java.net.SocketException in accept() which will terminate the loop and the thread.
final ServerSocket serverSocket = new ServerSocket(8000);
new Thread(new Runnable() {
public void run() {
while (true) {
try {
serverSocket.accept();
} catch (IOException e) {
return;
}
}
}
}).start();
Thread.sleep(10000);
serverSocket.close();
ServerSocket#setSoTimeout() may of your interest, that will abandon accept if a timeout was reached. Be aware of catch the SocketTimeoutException.
volatile boolean finishFlag = false;
while(true){
clientSocket = serverListener.accept();//Waiting for any client request
if ( finishFlag )
break;
//New thread started when request is received from any client
Thread thread =new Thread(new serverThread(clientSocket), "ClientThread");
thread.start();
}
EDIT:
for interrupting listener, you should stop this thread from outside, and then accept( ) will throws IOException
try {
while (true) {
Socket connection = server.accept( );
try {
// any work here
connection.close( );
}
catch (IOException ex) {
// maybe the client broke the connection early.
}
finally {
// Guarantee that sockets are closed when complete.
try {
if (connection != null) connection.close( );
}
catch (IOException ex) {}
}
}
catch (IOException ex) {
System.err.println(ex);
}