Server program taking lots of CPU even when not in use [closed] - java

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
I have a client/server java game im working on. There's a bunch of code and im trying to paste as little as possible while still giving enough.
When I first start the server, it takes no CPU. When my first game client connects, it jumps to 25%(which seems quite high for what it does, but thats not my main concern yet). The problem is, even when the client disconnects, the CPU usage of the server app remains at 25%.
The server takes a name from the client and constantly receives x, y coordinates from the player.
Here is the code for my actual server that is run once the server is started: (I apologize beforehand for the excessive indentation)
TCPServer(int port) {
try
{
tcpSock = new ServerSocket(port);
int z = 0;
while(true)
{
Socket sock = tcpSock.accept();
sock.setKeepAlive(true);
clientList.addElement(new TcpClient(sock));
clientList.get(z).cr.start();
clientList.get(z).cw.start();
clientList.get(z).packs.addElement("?");
while(!clientList.get(z).cr.nameRecieved)
{
//do nothing untill client has provided it's name
}
playerList.addElement(new player(sock.getInetAddress(), clientList.get(z).cr.playerName));
playerList.get(z).id=z;
playerList.get(z).name=clientList.get(z).cr.playerName;
clientList.get(z).packs.addElement("2 " + z);
for(int j =0; j<playerList.size();j++)
{
String status;
if(playerList.get(j).Connected)
status = "1";
else
status = "0";
addToQueue("3 " + playerList.get(j).id + " "
+ playerList.get(j).name + " " + playerList.get(j).x + " " + playerList.get(j).y + " " +
playerList.get(j).area + " " + status + " " );
}
z++;
addToQueue("4 " + z);
}
}
catch (IOException e) {
System.out.print(e);
}
}
And here is code that is run for each client. I have commented out a large portion of it for readability, the code just calculates and updates various location information. I think the problem is occurring somewhere here in this class.
public class TcpClient {
Socket sock;
ObjectInputStream in;
ObjectOutputStream out;
ClientRead cr;
ClientWrite cw;
public Vector<String> packs = new Vector<String>();
TcpClient(Socket s) {
this.sock = s;
try
{
sock.setKeepAlive(true);
}
catch(Exception e)
{
System.out.print(e);
}
cr = new ClientRead();
cw = new ClientWrite();
}
public class ClientRead extends Thread {
public boolean nameRecieved = false;
public boolean reading = true;
String playerName;
public void run(){
try{
in = new ObjectInputStream(sock.getInputStream());
while(sock.isConnected() && reading)
{
//code to retrieve and update user location
}
}
catch(Exception e){
System.out.print(e);
}
}
}
And finally, a short class to write information to the client:
public class ClientWrite extends Thread {
public boolean writing = true;
public void run() {
try{
out = new ObjectOutputStream(sock.getOutputStream());
out.flush();
while(sock.isConnected() && writing)
{
out.flush();
while(!packs.isEmpty())
{
out.writeObject(packs.firstElement());
System.out.print(packs.firstElement());
packs.remove(0);
out.flush();
}
}
}
catch(Exception e)
{
System.out.print(e);
}
}
}
I know there's a ton of code but if somebody sees anyting that immediately jumps out (especially with the threads) that can explain the behavior im getting. To recap, the server stays at 0% cpu until a client connects. After the first client connects, no matter how many more connect, it stays from 25%-30% CPU. However, when all of the client have disconnected, the CPU STAYS at that 25%-30% instead of going back down to 0.

The problem is here:
while(!clientList.get(z).cr.nameRecieved)
{
//do nothing untill client has provided it's name
}
It is a spin loop that smokes the CPU. You're doing this all wrong. As soon as you have accepted the socket, you must start a new thread to handle it. That thread should block until the client has provided its name as part of your protocol handshake, and then update your data structures. The accept loop shouldn't do anything except accept connections and start threads.

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.

Why TCP client can't detect server closed using write?

I am building an IM application, from the client side, I write my code like this (I use SocketChannel in blocking mode, history reason, I think it is not related to this problem):
try {
LogUtil.info(TAG, this.label + " tryConnect, attempt = " + (3 - retry));
clientChannel = SocketChannel.open();
clientChannel.configureBlocking(true);
clientChannel.socket().setSoTimeout(100);
clientChannel.socket().setTrafficClass(0x10);
clientChannel.socket().setTcpNoDelay(true);
clientChannel.socket().setPerformancePreferences(3, 3, 1);
clientChannel.socket().connect(address, 10000);
LogUtil.info(TAG, this.label + " socket connected successfully");
break;
} catch (AlreadyConnectedException ace) {
LogUtil.info(TAG, label + " AlreadyConnectedException");
break;
} catch (NotYetConnectedException ace) {
LogUtil.info(TAG, label + " NotYetConnectedException");
break;
} catch (SocketTimeoutException e) {
LogUtil.info(TAG, label + " SocketTimeoutException");
break;
} catch (Exception e) {
clientChannel = null;
throw new SocketConnectionException(label + ", exception = " + ThrowableUtil.stackTraceToString(e));
}
The problem is, when sometimes I shut down the server, the client-side will keeps writing successfully (small chunks of data, less than 50 bytes in total). After about 3 minutes, the client side hits the write fail exception.
Why didn't the client side fail immediately after the server has been closed? How do I fix this problem? Maybe reduce the send buffer to 10 bytes ?
EDIT
Here's how I actually write data:
public void writeXML(ByteBuffer buffer, int retry) {
synchronized (writeLock) {
if (retry < 0) {
throw new SocketConnectionException(label + "Write Exception");
}
tryConnect(false);
try {
int written = 0;
while (buffer.hasRemaining()) {
// I think it should be an exception here after I closed server
written += clientChannel.write(buffer);
}
if (LogUtil.debug) {
LogUtil.info(TAG, "\t successfully written = " + written);
}
} catch (Exception e) {
e.printStackTrace();
tryConnect(true);
writeXML(buffer, --retry);
}
}
}
Because in between you and the peer application there are:
a socket send buffer
a TCP implementation
another TCP implementation
a socket receive buffer.
Normally when you write, the data just gets transferred into your socket send buffer and is sent on the wire asynchronously. So if there is going to be an error sending it you won't find out straight away. You will only find out when the TCP sends have failed enough times over whatever the internal send timeout period is for TCP to decide that an error condition exists. The next write (or read) after that will get the error. It could be some minutes away.
It turns out that the read operation can detect a closed connection(via #EJP's reply, it is different from a lost connection) immediately.
In my reading thread, I have this line:
int read = clientChannel.read(buffer);
, When it returns -1 means the server is shutdown (Shutdown on purpose is different than network unreachable), I guess the write operation needs to fill the TCP send buffer, so there's no way to detect a connection lost quickly.

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.

Trying to get data from textfield to ouputstream for a chat program in Java

i'm working on a simple GUI chat program in Java. The goal is for the user to choose whether to host a server or to connect as a client. All of this works. The problem I'm having is letting either the client or the server chat. ideally, the user or the server can type into the textField and hit enter (or press the send button), and then the message will be sent to every client that is connected. During execution, the server runs an infinite while loop where it waits for more clients. The problem I'm having is two-fold:
1) I'm not sure if the way I'm passing the string to the inputstream is right, and 2) I don't know when I can have the server receive and then re-send the data, since it waits at server.accept().
here's the run method:
public void run()
{
conversationBox.appendText("Session Start.\n");
inputBox.requestFocus();
while (!kill)
{
if (isServer)
{
conversationBox.appendText("Server starting on port " + port + "\n");
conversationBox.appendText("Waiting for clients...\n");
startServer();
}
if (isClient)
{
conversationBox.appendText("Starting connection to host " + host + " on port " + port + "\n");
startClient();
}
}
}
here's the startClient method:
public void startClient()
{
try
{
Socket c = new Socket(host, port);
in = new Scanner(c.getInputStream());
out = new PrintWriter(c.getOutputStream());
while (true)
{
if (in.hasNext())
{
Chat.conversationBox.appendText("You Said: " + message);
out.println("Client Said: " + message);
out.flush();
}
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
and here's the startServer method:
public void startServer()
{
try
{
server = new ServerSocket(port);
while (true)
{
s = server.accept();
conversationBox.appendText("Client connected from " + s.getLocalAddress().getHostName() + "\n");
}
}
catch (Exception e)
{
conversationBox.appendText("An error occurred.\n");
e.printStackTrace();
isServer = false;
reEnableAll();
}
}
And finally, here's the part of actionPerformed where I get the data and (attempt) to write it to the outputstream:
if (o == sendButton || o == inputBox)
{
if(inputBox.getText() != "")
{
out.println(inputBox.getText());
inputBox.setText("");
}
}
I guess my question is: How can I rearrange my methods so that the server can wait for text from the client and then send it back to all the clients? And, how do I send the text from the client to the server?
Among the problems with this code:
You keep creating clients and servers. Surely you should only do one of each?
You are performing blocking network operations on the event thread instead of in a separate thread.
You are looping at EOS via while (true) ... if in.hasNext(). This should be while (in.hasNext()) ...
You are accepting a socket and not apparently doing anything with it. It looks like you can only handle one client at a time. You should start a new thread to handle each accepted socket.

Java network code not sending

I'm writing my first non-trivial Java app that uses:
networking
a GUI
threads
It's a IM program. When I send a message, the server doesn't output what it should. I'm sorry this description is so bad, but I don't know how to narrow the problem down further.
public class MachatServer {
//snip
public static void sendMessage(int targetId, int fromId, String message) {
ConnectedClient targetClient = getClient(targetId);
// Also runs
System.out.println("Sending message: " + message + "\n\nfrom " + fromId + " to " + targetId);
targetClient.addOutCommand("/message:" + fromId + ":" + message + "\n");
}
}
class ConnectedClient implements Runnable {
public void run() {
String contact;
contact = s.getInetAddress().toString();
System.out.println("Connected to " + contact);
try {
out.write("/connected" + "\n");
out.flush();
String command;
while(true) {
if(shouldExit) {
s.close();
break;
}
if(in.hasNextLine()) {
command = in.nextLine();
commandProcessor.addInCommand(command);
}
Thread.sleep(100);
}
} catch(Exception e) {
e.printStackTrace();
}
}
// snip
public void addOutCommand(String command) {
commandProcessor.addOutCommand(command);
//
// My guess is that the problem is with this method as the next line
// Does not print out.
//
//
System.out.println("" + thisId + " recieved to send: " + command);
}
}
class CommandProcessor implements Runnable {
// snip
public void run() {
String currentCommandIn;
String currentCommandOut;
while(true) {
try {
currentCommandIn = inQueue.poll();
if(currentCommandIn != null) {
System.out.println("Processing: " + currentCommandIn);
String[] commandArr = CommandParser.parseRecievedCommand(currentCommandIn);
if(commandArr[0].equalsIgnoreCase("message")) {
int target = Integer.parseInt(commandArr[1]);
String message = commandArr[2];
// This definetly runs
System.out.println("Message sending to: " + target);
MachatServer.sendMessage(target, this.conId, message);
} else if(commandArr[0].equalsIgnoreCase("quit")) {
// Tell the server to disconnect us.
MachatServer.disconnect(conId);
break;
}
currentCommandOut = outQueue.poll();
if(currentCommandOut != null) {
try {
out.write(currentCommandOut + "\n");
System.out.println(currentCommandOut + "sent");
out.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
} catch(Exception e) {
e.printStackTrace();
}
public synchronized void addOutCommand(String command) {
if(command != null) {
try {
outQueue.push(command);
} catch(Exception e) {
System.out.println(command);
e.printStackTrace();
}
// Does not print
System.out.println("Ready to send: " + command);
} else {
System.out.println("Null command recieved");
}
//snip
}
The full source code is at my github, in case I have narrowed the problem down incorrectly.
The expected output should be when I telnet in and send "/message:0:test", it should send "/message:myid:test" to the client with ID 0. The actual output is nothing.
This is probably not a complete answer, but there are a few serious issues with your code that could be the cause of your problem, so you should fix those first.
First, the loop in CommandProcessor.run is busy-waiting, i.e., it runs constantly. You should use blocking operations. Also, inQueue and outQueue are accessed from two different threads so you need synchronization on every access. I recommend using something implementing the java.util.concurrent.BlockingQueue interface to solve both issues. And finally, when checking your full code, it appears that you also need to synchronize access to the ConnedtedClient.shouldExit field (I believe you can use `java.util.concurrent.atomic.AtomicBoolean as a replacement but I'm not sure).
And the reason why this could be the cause of your problem: Since CommandProcessor.run is not synchronizing on anything (or accessing anything volatile), the Java virtual machine can assume that nothing from outside can modify anything it examines, so in theory, when the run method first notices that inQueue and outQueue are both empty, it can optimize the whole method into nothing, as it can assume that it is the only thing that can modify them. But I don't know whether this can actually happen in practice, as the JVM needs to know quite a bit about the LinkedList implementation and notice that the thread is just doing these two checks in a loop. But it's always best to be safe because that way your code is guaranteed to work.
The field outQueue is uninitialized in CommandProcessor, and you commented out the printStackTrace() that would have helped you figure it out.
Maybe the problem is that the data you send is to short....
A friend of mine had a similar problem a couple of years ago, and it turned out the data was being buffered until it had enough data to send...
It had something to do with optimizing the amount of network traffic... I believe he mentioned something called "Nagle's algorithm" when he finally solved it....
Hope this can be of some help...

Categories