Java Server having many clients connect without bottlenecking - java

So what I'm trying to do is have a socket that receives input from the client, put the client into the queue and then return a message to each client in the queue when my algorithm returns true.
This queue should support a few hundred clients at once but at the same time not bottle neck the server so it can actually do what its supposed to do.
This is what i have so far:
private static final int PORT = 25566;
private static final int THREADS = 4;
private ExecutorService service;
public void init() throws IOException, IllegalStateException {
ServerSocket serverSocket;
serverSocket = new ServerSocket(PORT);
service = Executors.newCachedThreadPool();
Socket socket;
while(true) {
socket = serverSocket.accept();
System.out.println
("Connection established with " + socket.getInetAddress().toString());
service.execute(() -> {
Scanner scanner = null;
PrintWriter output = null;
String line = null;
try {
scanner = new Scanner(new InputStreamReader(socket.getInputStream()));
output = new PrintWriter(socket.getOutputStream());
} catch(IOException e) {
e.printStackTrace();
}
try {
if (scanner == null || output == null)
throw new IllegalStateException("Scanner/PrintWriter is " + "null!");
line = scanner.nextLine();
while (line.compareTo("QUIT") != 0) {
/* This is where input comes in, queue for the algorithm,
algorithm happens then returns appropriate values */
output.flush();
line = scanner.nextLine();
}
} finally {
try {
System.out.println
("Closing connection with " + socket.getInetAddress().toString());
if(scanner != null) {
scanner.close();
}
if(output != null) {
output.close();
}
socket.close();
} catch(IOException e) {
e.printStackTrace();
}
}
});
}
}
Now what I think will happen with this, is if the queues do reach high enough levels, my thread pool will completely bottleneck the server as all of the threads are being put to use on handling the clients in the queue and there won't be enough processing for the algorithm.
EDIT: After a bunch of testing, I think it will work out if in the algorithm it returns the value then disconnects, not waiting for user response but having the users client reconnect after certain conditions are met.

Your bottleneck is unlikely to be processing power unless you are machine limited. What's more likely to happen is that all the threads in your thread pool are consumed and end up waiting on input from the clients. Your design can only handle as many clients at once as there are threads in the pool.
For a few hundred clients, you could consider simply creating a thread for each client. The limiting resource for the number of threads that can be supported is typically memory for the stack that each thread requires, not processing power; for a modern machine with ample memory, a thousand threads is not a problem, based on personal experience. There may be an operating system parameter limiting the number of threads which you may have to adjust.
If you need to handle a very large number of clients, you can set up your code to poll sockets for available input and do the processing only for those sockets that have input to be processed.

Related

How to stream data from one part of a Java program to another?

I've learned in Java how to stream data over a network connection using ServerSocket and Socket, such as:
Client.java:
Socket socket = new Socket(address, port);
int i;
while ((i = System.in.read()) != -1)
socket.getOutputStream().write(i);
Server.java:
ServerSocket server = new ServerSocket(port);
Socket socket = server.accept();
int i;
while ((i = socket.getInputStream().read()) != -1)
System.out.println(i);
This would simply have Client blocking on System.in.read() at one end, and Server blocking on socket.getInputStream().read() at the other, and the bytes get passed when ENTER is pressed in the Client program.
How would I accomplish something similar within a single program, without using Sockets? For example, if I had Thread A waiting on keyboard input which is then streamed to Thread B which is able to "consume" the bytes at an arbitrary time in the future, just as Server (above) is able to consume bytes from socket.getInputStream() at some arbitrary time?
Is PipedInput/OutputStream the right solution for this, or ByteArrayInput/OutputStream, or something else? Or am I overthinking it?
Yes, you can use PipedInputStream/PipedOutputStream for "streaming" data "locally" in your JVM. You create one PipedInputStream and one PipedOutputStream instance, connect them with the connect() method and start sending/receiving bytes. Check the following example:
PipedInputStream pipedIn = new PipedInputStream();
PipedOutputStream pipedOut = new PipedOutputStream();
pipedIn.connect(pipedOut);
Thread keyboardReadingThread = new Thread() {
#Override
public void run() {
System.out.println("Enter some data:");
Scanner s = new Scanner(System.in);
String line = s.nextLine();
System.out.println("Entered line: "+line);
byte[] bytes = line.getBytes(StandardCharsets.UTF_8);
try {
pipedOut.write(bytes);
pipedOut.flush();
pipedOut.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Keyboard reading thread terminated");
}
};
keyboardReadingThread.start();
Thread streamReadingThread = new Thread() {
#Override
public void run() {
try {
int bytesRead = 0;
byte[] targetBytes = new byte[100];
System.out.println("Read data from the PipedInputStream instance");
while ((bytesRead = pipedIn.read(targetBytes)) != -1) {
System.out.println("read "+bytesRead+" bytes");
String s = new String(targetBytes, 0, bytesRead, StandardCharsets.UTF_8);
System.out.println("Received string: "+s);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Streaming reading thread terminated");
}
};
streamReadingThread.start();
keyboardReadingThread.join();
streamReadingThread.join();
First the two piped stream instances are connected. After that two threads will read from the keyboard and read from the PipedInputStream instance. When you run your application you will get an output similar to this (with Some example input for testing being the keyboard input):
Enter some data:
Read data from the PipedInputStream instance
Some example input for testing
Entered line: Some example input for testing
Keyboard reading thread terminated
read 30 bytes
Received string: Some example input for testing
Streaming reading thread terminated
Also notice that the threads are not synchronized in any way, so the System.out.println() statements might get executed in a different order.
This is mostly an extension of the answer #VGR gave in the comments.
If the entirety of your "Network" exists within the same, single JVM, then you don't need anything like sockets at all - you can just use Objects and methods.
The entire point of Sockets was to allow the JVM to perform actions outside of itself (typically with another JVM somewhere in the outside world).
So unless you are trying to interact with objects outside of your current JVM, it is as simple as this.
public class ClientServerExample
{
public static void main(String[] args)
{
Server server = new Server();
Client client = new Client();
client.sendMessage("Hello Server", server);
}
static class Server
{
String respond(String input)
{
String output = "";
System.out.println("Server received the following message -- {" + input + "}");
//do something
return output;
}
}
static class Client
{
void sendMessage(String message, Server server)
{
System.out.println("Client is about to send the following message to the server -- {" + message + "}");
String response = server.respond(message);
System.out.println("Client received the following response from the server -- {" + response + "}");
//maybe do stuff with the response
}
}
}
Here is the result from running it.
Client is about to send the following message to the server -- {Hello Server}
Server received the following message -- {Hello Server}
Client received the following response from the server -- {}
Note that server doesn't return anything because I didn't do anything in the server. Replace that comment with some code of your own and you will see the results.
EDIT - to better explain a real world example, where a server will respond to requests in FIFO, here is a modified version of the above example.
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
public class ClientServerExample
{
public static void main(String[] args)
{
System.out.println("===========STARTING SYNCHRONOUS COMMUNICATION============");
synchronousCommunication();
System.out.println("===========FINISHED SYNCHRONOUS COMMUNICATION============");
System.out.println("===========STARTING ASYNCHRONOUS COMMUNICATION============");
asynchronousCommunication();
System.out.println("===========FINISHED ASYNCHRONOUS COMMUNICATION============");
}
public static void synchronousCommunication()
{
Server server = new Server();
Client client = new Client();
String response = "";
response = client.sendMessage("Good morning Server!", server).join();
System.out.println("Client received the following response from the server -- {" + response + "}");
response = client.sendMessage("Good evening Server!", server).join();
System.out.println("Client received the following response from the server -- {" + response + "}");
}
public static void asynchronousCommunication()
{
Server server = new Server();
Client client = new Client();
List<CompletableFuture<String>> responses = new ArrayList<>();
responses.add(client.sendMessage("Good morning Server!", server));
responses.add(client.sendMessage("Good evening Server!", server));
for (CompletableFuture<String> eachResponse : responses)
{
System.out.println("Client received the following response from the server -- {" + eachResponse.join() + "}");
}
}
static class Server
{
CompletableFuture<String> respond(final String input)
{
System.out.println("Server received the following message -- {" + input + "}");
return
CompletableFuture.supplyAsync(
() ->
{
try
{
//sleep for 2 seconds, to represent arbitrary delay in receiver processing
Thread.sleep(2000);
return input.contains("morning") ? "Good morning to you too!" : "Good evening to you too!";
}
catch (Exception e)
{
throw new IllegalStateException("What happened?", e);
}
});
}
}
static class Client
{
CompletableFuture<String> sendMessage(String message, Server server)
{
System.out.println("Client is about to send the following message to the server -- {" + message + "}");
return server.respond(message);
}
}
}
Both of these examples are performing a FIFO approach to data processing. They receive the request, calculate a response, and then send back a CompletableFuture, which is basically an Object that contains the response that will arrive once the Server gets around to it, sort of like a Promise in Javascript.
For the synchronous example, we see that a client message is sent, and then processed before the next one is sent. As a result, we have a minor delay between the 2 (about 2 seconds).
For the asynchronous example, we see that both client messages are sent, and their CompletableFutures are put into a batch list, which is converted to normal strings once all requests have been sent.
The synchronous example takes around 10 seconds.
The asynchronous example takes around 5 seconds.
Both of these are different ways of performing FIFO in the way that you described. They both are examples where multiple clients send a request to the server, and then the server finishes them when they get around to it. That 5 seconds delay is meant to represent the idea of "getting around to it". In reality, getting around to it usually means that the server has so much on it's plate that it will take a long time before it has a chance to give a full response.
Let me know if you need another example to better help you understand.

Two Threads Executing Same Method

I am developing an API request and I'm using multi threading.In the output I'm getting the same request twice generated by two threads.As I debugged two thread are calling the same method again.So need help so that this issue is resolved
This is my pseudo code
public void run() {
logger.debug("Thread " + currentThread().getName() + " Running");
String message = "";
Connection connection = null;
InputStream fileinput = null;
Properties properties = new Properties();
try {
File file = new File("/home/sridhar.anirudh/eclipse-workspace/API/Change.properties");
fileinput = new FileInputStream(file);
properties.load(fileinput);
soapEndpointUrl = properties.getProperty("endpoint_url");
soapAction = properties.getProperty("soap_action");
} catch (Exception e) {
e.printStackTrace();
}
try {
connection = Database.getInstance().getConnection();
} catch (SQLException e1) {
logger.error("Failed To Get Connection " + e1.getMessage());
return;
}
if (CATEGORY.equalsIgnoreCase("fraudrestriction")) {
String soapResponse = callSoapWebServiceFraudRestriction(soapEndpointUrl, soapAction);
String response_status = "";
if (soapResponse.contains("<tns:Description>SUCCESS</tns:Description>") &&
soapResponse.contains("<tns:Code>ERR_000</tns:Code>")) {
response_status = "SUCCESS";
If you kick off two copies of the thread, they will both run, creating the effect you see.
You can create multiple worker threads, but you need to allocate the work between those workers such that each performs a subset of the total workload.
Since you're (seemingly) parsing and processing a file, and making a network service request in response to that file's contents, it's not clear how you intend to divide up the work. That's the key; to use multiple threads to improve throughput, you the programmer must devise a means of partitioning the work between those threads.
As an analogy, if you have one (human) worker working on a job, simply hiring a second worker won't get the job completed any faster unless the work is divided between those workers. That division is your problem. There's nothing magical about threads that can do this for you.

Only works in debugging mode

I'm trying to create a program for a distributed system. At the moment I have a thread for listening to connections, and a thread for sending, and a thread for receiving.
I've reached a problem where the client will connect but only when using breakpoints. I can't figure out the problem at all!. I've tried to implement things to slow the program down however nothing is working.
If you guys could take a look i'd be greatly appreciative.
public static void main(String[] args)
{
System.out.println("Server starting on port 5000");
RecievingConnection reciever = new RecievingConnection(5000,0); //Recieving Connection
reciever.start();
SendingConnection sender = new SendingConnection(5001,1); //Sending Connection
sender.start();
while(true){
while(reciever.ready==true){
System.out.println("In");
nodes first = new nodes(reciever.socket,0);
System.out.println("Node created");
first.start();
System.out.println("Client connected on port: " + reciever.socket.getLocalAddress());
nodes second = new nodes(sender.socket,1);
second.start();
reciever.ready=false;
sender.ready=false;
reciever.connectionComplete=true;
sender.connectionComplete=true;
}
}
}
public RecievingConnection(int port, int mode)
{
Serverport = port;
connectionMode = mode;
try{
server = new ServerSocket(port);
server.setSoTimeout(100000);
}
catch(IOException ex)
{
System.out.println(ex);
}
}
public void run(){
while(true){
if(ready == false){
try {
socket = server.accept();
ready = true;
System.out.println("Attempting to connect using port: " + Serverport);
while(connectionComplete == false){
//wait
}
} catch (IOException ex) {
System.out.println(ex);
}
}
}
}
The sending thread is basically the same code. Any idea what the problem is? "Nodes" is the thread for each node.
I solved it by adding a sleep in the main thread. I presume this is because the main thread takes priority over child threads?
Your problem is almost certainly at:
while (connectionComplete == false) {
//wait
}
This will loop forever, the other thtreads will not get any cpu time at all. It also explains why it works in debug - it's because in debug if you stop at a breakpoint, any other threads will get time.
You should at least do:
while (connectionComplete == false) {
//wait
Thread.sleep(0);
}
and maybe use a number much greater than 0. This will allow other thtreads a chance to run.
I am not suggesting that this will make your code work correctly but it should remove the current problem.
After that there's another tight loop that won't let any other thread time.
while (true) {
if (ready == false) {
Change that to:
while (true) {
if (ready == false) {
// ...
} else {
// Here too.
Thread.sleep(0);
}
}
You can't just share variables between threads. Make them volatile, synchronize or use CAS types like AtomicBoolean.
Read about it.
https://docs.oracle.com/javase/tutorial/essential/concurrency/interfere.html
http://www.journaldev.com/1061/java-synchronization-and-thread-safety-tutorial-with-examples
https://docs.oracle.com/javase/tutorial/essential/concurrency/atomicvars.html
Besides class "nodes" is not described here and classes are expected to start with an upper case letter.

How to add heartbeat messaging on top of this Java code( for KnockKnockClient/Server)?

I'm studying the following basic Java socket code( source ). It's a Knock-Knock-Joke client/server app.
In the Client, we set up the socket as usual:
try {
kkSocket = new Socket("localhost", 4444);
out = new PrintWriter(kkSocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(kkSocket.getInputStream()));
} catch( UnknownHostException uhe ){ /*...more error catching */
And then later, we just read and write to Server:
BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in));
String fromServer;
String fromUser;
while ((fromServer = in.readLine()) != null) {
System.out.println("Server: " + fromServer);
if (fromServer.equals("bye."))
break;
fromUser = stdIn.readLine();
if (fromUser != null){
System.out.println("Client: " + fromUser);
out.println(fromUser);
}
And on the server, we have the corresponding code, to get the joke punch-line.
KnockKnockProtocol kkp = new KnockKnockProtocol();
outputLine = kkp.processInput(null);
out.println(outputLine);
while ((inputLine = in.readLine()) != null) {
outputLine = kkp.processInput(inputLine);
out.println(outputLine);
if (outputLine.equals("Bye."))
break;
I want to attach a heartbeat to the whole thing, which will print out to the console whenever it detects that the other side died. Because what happens now if I kill the other side is an exception - like this one below:
So if I am running both KnockKnockClient and KnockKnockServer, then I shut down KnockKnockServer, what should happen is that on the Client I see this outputted:
>The system has detected that KnockKnockServer was aborted
I'm looking for any tips. So far I've mainly been trying to run a daemon thread that periodially creates new connections to the other side. But I'm confused about what condition to check for(but I think it's just a boolean value?). Is that the right approach? I just found out online there's a library called JGroups for multicast networking - would that be a better way? I'm looking for any tips.
My server-code so far(sorry it's messy)
&
Client-side
thanks
But the exception you are getting is exactly this! It's telling you that the other side just died. Just catch the exception and print to the console, that "The system has detected that KnockKnockServer was aborted".
You are using TCP connection and TCP has built-in heartbeat (keepalive) mechanism that will do this for you. Just set setKeepAlive() on the socket. That being said - It is possible to control keepalive frequency per each connection, but I do not know how to do that in java.
http://tldp.org/HOWTO/TCP-Keepalive-HOWTO/overview.html
https://stackoverflow.com/a/1480259/706650
you have a Synchronous communication. for having the heartbeat message, use an asynchronous communication. there will be 2 threads. one will read from the socket and another will keep writing to the socket. If you use asynchronous communication, the server will be sending a message every 10 seconds. the client thread will be reading messages from the server and if there is no message, it means the server is down. in your case, the server either sends back the message to client(if client has some message) or send an automatic reply.your server code can be modified like this.
Create a server thread that will keep sending messages to client every 10 seconds.
public class receiver extends Thread{
public static bool hearbeatmessage=true;
Socket clientSocket=new Socket();
PrintWriter out=new PrintWriter();
public receiver(Socket clientsocket){
clientSocket=clientsocket;
out = new PrintWriter(clientSocket.getOutputStream(), true);
}
public void run(){
while(true)
{
if(heartbeatmessage){
thread.sleep(10000);
out.println("heartbeat");
}
}
}
}
In your server code:
KnockKnockProtocol kkp = new KnockKnockProtocol();
outputLine = kkp.processInput(null);
out.println(outputLine);
receiver r=new reciver(clientSocket);
r.run(); /*it will start sending hearbeat messages to clients */
while ((inputLine = in.readLine()) != null) {
outputLine = kkp.processInput(inputLine);
reciver.hearbeatMessage=false; /* since you are going to send a message to client now, sending the heartbeat message is not necessary */
out.println(outputLine);
reciver.hearbeatMessage=true; /*start the loop again*/
if (outputLine.equals("Bye."))
break;
The client code will also be modified, a thread will keep reading messages from the socket and if it has not received message for more than 11 seconds(1 second extra), it will declare the server is not available.
Hope this helps. There might be some flaw in the logic too. Let me know.
The following are best practices which we apply on a daily base when interfacing with hardware (using sockets).
Good practice 1 : SoTimeout
This property enables a read timeout. The goal of this is to avoid the issue that Tom had. He wrote something in the line of : "you will need to wait till the next client message arrives". Well, this offers a solution to that problem. And it's also the key to implementing a heartbeat and many other checks.
By default, the InputStream#read() method will wait forever, until a message arrives. The setSoTimeout(int timeout) changes this behaviour. It will apply a timeout now. When it timeouts it will throw the SocketTimeoutException. Just catch the exception, check a couple of things and continue reading (repeat). So basically, you put your reading method in a loop (and probably even in a dedicated thread).
// example: wait for 200 ms
connection.setSoTimeout(200);
You can use these interruptions (caused by the timeout) to validate the status: E.g. how long has it been since I received my last message.
Here is an example to implement the loop:
while (active)
{
try
{
// some function that parses the message
// this method uses the InputStream#read() method internally.
code = readData();
if (code == null) continue;
lastRead = System.currentTimeMillis();
// the heartbeat message itself should be ignored, has no functional meaning.
if (MSG_HEARTBEAT.equals(code)) continue;
//TODO FORWARD MESSAGE TO ACTION LISTENERS
}
catch (SocketTimeoutException ste)
{
// in a typical situation the soTimeout should be about 200ms
// the heartbeat interval is usually a couple of seconds.
// and the heartbeat timeout interval a couple of seconds more.
if ((heartbeatTimeoutInterval > 0) &&
((System.currentTimeMillis() - lastRead) > heartbeatTimeoutInterval))
{
// no reply to heartbeat received.
// end the loop and perform a reconnect.
break;
}
// simple read timeout
}
}
Another use of this timeout: It can be used to cleanly stop your session by setting active = false. Use the timeout to check if this field is true. If that's the case, then break the loop. Without the SoTimeout logic this would not be possible. You would either be forced to do a socket.close() or to wait for the next client message (which clearly makes no sense).
Good practice 2 : Built-in Keep-Alive
connection.setKeepAlive(true);
Well basically this is pretty much what your heart-beat logic does. It automatically sends a signal after a period of inactivity and checks for a reply. The keep-alive interval is operating system dependent though, and has some shortcomings.
Good practice 3 : Tcp No-Delay
Use the following setting when you are often interfacing small commands that need to be handled quickly.
try
{
connection.setTcpNoDelay(true);
}
catch (SocketException e)
{
}
I think you are over complicating things.
From the client side:
If the client gets an IOException for the connection reset, then this means the server is dead. Instead of printing the stack trace just do what ever you need to do once you know that the server is down. You already know the server is down due to the exception.
From the server side:
Either start a timer and if you don't get a request for a time more than the interval assume that the client is down.
OR start a background server thread at the client (making the client and server peers) and have the server send a "dummy" hearbeat request (server now acts as a client). If you get exception the client is down.
Figured I'd take a crack at this... I started with the KnockKnockServer and KnockKnockClient that are on the Java site (in your original question).
I didn't add any threading, or heartbeats; I simply changed the KnockKnockClient to the following:
try { // added try-catch-finally block
while ((fromServer = in.readLine()) != null) {
System.out.println("Server: " + fromServer);
if (fromServer.equals("Bye."))
break;
fromUser = stdIn.readLine();
if (fromUser != null) {
System.out.println("Client: " + fromUser);
out.println(fromUser);
}
}
} catch (java.net.SocketException e) { // catch java.net.SocketException
// print the message you were looking for
System.out.println("The system has detected that KnockKnockServer was aborted");
} finally {
// this code will be executed if a different exception is thrown,
// or if everything goes as planned (ensure no resource leaks)
out.close();
in.close();
stdIn.close();
kkSocket.close();
}
This seems to do what you want (even though I modified the original Java website example, rather than your code - hopefully you'll be able to see where it plugs in). I tested it with the case you described (shut down the server while the client is connected).
The downside to this is that, while the client is waiting for user input, you don't see that the server has died; you have to enter client input, and then you'll see that the server has died. If this is not the behavior you want, please post a comment (perhaps that was the whole point of the question - it just seemed like you might have been going down a longer road than you needed in order to get to where you wanted to be).
Here's a slight modification to the client. It doesn't use an explicit heartbeat, but as long as you keep reading from the server, you'll immediately detect the disconnect anyway.
This is because readLine will immediately detect any read errors.
// I'm using an anonymous class here, so we need
// to have the reader final.
final BufferedReader reader = in;
// Decouple reads from user input using a separate thread:
new Thread()
{
public void run()
{
try
{
String fromServer;
while ((fromServer = reader.readLine()) != null)
{
System.out.println("Server: " + fromServer);
if (fromServer.equals("Bye."))
{
System.exit(0);
}
}
}
catch (IOException e) {}
// When we get an exception or readLine returns null,
// that will be because the server disconnected or
// because we did. The line-break makes output look better if we
// were in the middle of writing something.
System.out.println("\nServer disconnected.");
System.exit(0);
}
}.start();
// Now we can just read from user input and send to server independently:
while (true)
{
String fromUser = stdIn.readLine();
if (fromUser != null)
{
System.out.println("Client: " + fromUser);
out.println(fromUser);
}
}
In this case, we allow client writes even when we're waiting for reply from the server. For a more stable application, we'd want to lock the input while we're waiting for a reply by adding a semaphore controlling when we start reading.
These are the modifications we would make to control the input:
final BufferedReader reader = in;
// Set up a shared semaphore to control client input.
final Semaphore semaphore = new Semaphore(1);
// Remove the first permit.
semaphore.acquireUninterruptibly();
new Thread()
... code omitted ...
System.out.println("Server: " + fromServer);
// Release the current permit.
semaphore.release();
if (fromServer.equals("Bye."))
... code omitted ...
while (true)
{
semaphore.acquireUninterruptibly();
String fromUser = stdIn.readLine();
... rest of the code as in the original ...
I think #Bala's answer is correct on server side. I'd like to give a supplementary on client side.
On client side, you should:
use an variable to keep the timestamp of the last message from server;
start a thread which runs periodically(every 1 second, e.g.) to compare current timestamp and the last message timestamp, if it is longer than desired timeout(10 seconds, e.g.), a disconnection should be reported.
Following are some code snippet:
The TimeoutChecker class(thread):
static class TimeoutChecker implements Runnable {
// timeout is set to 10 seconds
final long timeout = TimeUnit.SECONDS.toMillis(10);
// note the use of volatile to make sure the update to this variable thread-safe
volatile long lastMessageTimestamp;
public TimeoutChecker(long ts) {
this.lastMessageTimestamp = ts;
}
#Override
public void run() {
if ((System.currentTimeMillis() - lastMessageTimestamp) > timeout) {
System.out.println("timeout!");
}
}
}
Start the TimeoutChecker after connection is established:
try {
kkSocket = new Socket("localhost", 4444);
// create TimeoutChecker with current timestamp.
TimeoutChecker checker = new TimeoutChecker(System.currentTimeMillis());
// schedule the task to run on every 1 second.
ses.scheduleAtFixedRate(, 1, 1,
TimeUnit.SECONDS);
out = new PrintWriter(kkSocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(kkSocket.getInputStream()));
} catch( UnknownHostException uhe ){ /*...more error catching */
The ses is a ScheduledExecutorService:
ScheduledExecutorService ses = Executors.newScheduledThreadPool(1);
And remember to update the timestamp when receiving messages from server:
BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in));
String fromServer;
String fromUser;
while ((fromServer = in.readLine()) != null) {
// update the message timestamp
checker.lastMessageTimestamp = System.currentTimeMillis();
System.out.println("Server: " + fromServer);
if (fromServer.equals("bye."))
break;
Adel,was looking at your code http://pastebin.com/53vYaECK
Can you try the following solution. not sure whether it will work.
instead of creating a bufferedreader with the inputstream once,
we can create an instance of BufferedReader eachtime.
when the kkSocket.getInputStream is null, it comes out of the while loop and set completeLoop to false, so that we exit the while loop.
it has 2 while loops and the objects are created each time.
if the connection is open but does not have data in it inputstream will not be null,
BufferedReader.readLine would be null.
bool completeLoop=true;
while(completeLoop) {
while((inputstream is=kkSocket.getInputStream())!=null) /*if this is null it means the socket is closed*/
{
BufferedReader in = new BufferedReader( new InputStreamReader(is));
while ((fromServer = in.readLine()) != null) {
System.out.println("Server: " + fromServer);
if (fromServer.equals("Bye."))
break;
fromUser = stdIn.readLine();
if (fromUser != null) {
System.out.println("Client: " + fromUser);
out.println(fromUser);
}
}
}
completeLoop=false;
System.out.println('The connection is closed');
}

easiest and best way to make a server queue java

i have a server at the moment which makes a new thread for every user connected but after about 6 people are on the server for more than 15 mins it tends to flop and give me java heap out of memory error i have 1 thread that checks with a mysql database every 30 seconds to see if any of the users currently logged on have any new messages. what would be the easiest way to implement a server queue?
this is the my main method for my server:
public class Server {
public static int MaxUsers = 1000;
//public static PrintStream[] sessions = new PrintStream[MaxUsers];
public static ObjectOutputStream[] sessions = new ObjectOutputStream[MaxUsers];
public static ObjectInputStream[] ois = new ObjectInputStream[MaxUsers];
private static int port = 6283;
public static Connection conn;
static Toolkit toolkit;
static Timer timer;
public static void main(String[] args) {
try {
conn = (Connection) Mysql.getConnection();
} catch (Exception ex) {
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.println("****************************************************");
System.out.println("* *");
System.out.println("* Cloud Server *");
System.out.println("* ©2010 *");
System.out.println("* *");
System.out.println("* Luke Houlahan *");
System.out.println("* *");
System.out.println("* Server Online *");
System.out.println("* Listening On Port " + port + " *");
System.out.println("* *");
System.out.println("****************************************************");
System.out.println("");
mailChecker();
try {
int i;
ServerSocket s = new ServerSocket(port);
for (i = 0; i < MaxUsers; ++i) {
sessions[i] = null;
}
while (true) {
try {
Socket incoming = s.accept();
boolean found = false;
int numusers = 0;
int usernum = -1;
synchronized (sessions) {
for (i = 0; i < MaxUsers; ++i) {
if (sessions[i] == null) {
if (!found) {
sessions[i] = new ObjectOutputStream(incoming.getOutputStream());
ois[i]= new ObjectInputStream(incoming.getInputStream());
new SocketHandler(incoming, i).start();
found = true;
usernum = i;
}
} else {
numusers++;
}
}
if (!found) {
ObjectOutputStream temp = new ObjectOutputStream(incoming.getOutputStream());
Person tempperson = new Person();
tempperson.setFlagField(100);
temp.writeObject(tempperson);
temp.flush();
temp = null;
tempperson = null;
incoming.close();
} else {
}
}
} catch (IOException ex) {
System.out.println(1);
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
}
}
} catch (IOException ex) {
System.out.println(2);
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
}
}
public static void mailChecker() {
toolkit = Toolkit.getDefaultToolkit();
timer = new Timer();
timer.schedule(new mailCheck(), 0, 10 * 1000);
}
}
It seems like you have a memory leak. 6 threads is not much. I suspect it is because ObjectInputStream and ObjectOutputStream cache all the objects transmitted. This makes them quite unsuitable for long transfers. You think you are sending an object that is then gc'ed, but it's really being held in memory by the object streams.
To flush the streams cache, use
objectOutputStream.reset()
after writing your objects with writeObject()
EDIT:
To get thread pooling, the SocketHandler can be passed to an Executor instead of starting it's own thread. You create an executor like:
Executor executor = Executors.newFiexThreadPool(MaxUsers);
The executor is created as a field, or at the same level as the server socket. Then after
accepting a connection you add the SocketHandler to the executor:
executor.execute(new SocketHandler(...));
However, if your clients are long lived, then this will make little improvement, since the thread startup time is small compared to the amount of work done on each thread. Pools are most effective for executing many small tasks, rather than a few large ones.
As to making the server more robust - some quick hints
ensure it is started with sufficient memory, or at least that the maximum memory is set to anticipate the need of 1000 users.
use a load test framework, such as Apache JMeter to verify it will scale to the maximum number of users.
use a connection pool for your database, and don't hand-code JDBC calls - use an established framework, e.g. Spring JDBC.
Each thread starts with 2MB stack by default. So, if you have 1000 users, then that will use ~2GB of virtual process space just for the stack. ON many 32-bit systems, this is the amount of user space you can have, so there will be no room for data. If you need more users, then either scale out to more processes, with a load balancer passing requests to each process, or look at server solutions that do not require a thread per connection.
attention to detail, particularly exception handling.
logging, for diagnosing failures.
JMX or other managability to monitor server health, with notification to you when values go out of bounds (e.g. memory/cpu use too high for a long period, or request time slow.)
See Architecture of a Highly Scalable Server
You should check out Java NIO for building scalable servers
I would focus attention on why you are running out of heap space, or rather why your program gets an OOM error when 6 connections have been open for some time. Your server should be able to scale to at least many more simultaneous concurrent connections, but it's hard to quantify that number without getting more details about your environment, HW, etc.
You've only posted the main method for your server so it's hard to tell if there are memory leaks, resource leaks, etc. that might be causing you to run out of heap space. Are you running your server with the default heap settings? If so, you might want to try increasing your heap size, as the defaults are quite conservative.
Romain is correct: you should be closing your stream resources in a try { ... } finally { ... } block to make sure you are not leaking resources.
Lastly, you might want to consider passing the backlog parameter to the ServerSocket constructor. This specifies the maximum queue size for incoming connections to that ServerSocket, after which any new connections are refused. But first you still need to figure out why your server cannot handle more than 6 connections.

Categories