Reputation:
I am trying to keep a connection open for a multithreaded server program. When I hit a button, I want it to send a test message to all clients that are connected.
public void run() {
try {
Scanner in = new Scanner(socket.getInputStream());
PrintWriter out = new PrintWriter(socket.getOutputStream());
readUpdate(out, in);
while(true){sendUpdate(out);}
} catch (Exception e) {
e.printStackTrace();
}
}
Uses way to much CPU.
This is my sendUpdate method.
private void sendUpdate(final PrintWriter out) {
new Thread(new Runnable() {
public void run() {
if(Server.send) {
try {
if (Server.command != "idle") {
System.out.println("Sending");
out.println("!msg@" + Server.command);
out.flush();
Server.send = false;
Thread.sleep(100);
}
} catch (Exception ex) {
}
}
}
}).start();
}
If somebody can help me keep the connection open, and ready to send data, I would appreciate it.
Upvotes: 1
Views: 920
Reputation: 81054
If your server can initiate messages and so can your client, you probably want a separate thread reading and writing. One thread makes sense for request-response style communication, where you can block on the next client request, do some server-side processing, respond to the client, and then block again.
But if you need to block on two separate conditions (receiving a message from the client and you clicking the button on the server) then you should have two separate threads. Otherwise, you will find yourself needing to repeatedly wake your thread up to check if either of the conditions are true.
So create two threads, and give one your Scanner
(that does the readUpdate
logic) and the other your PrintWriter
. This is what your output handler could look like:
public class WriteHandler implements Runnable {
private final PrintWriter out;
private final BlockingQueue<String> messageQueue = new LinkedBlockingQueue<String>();
//initialize the above in a constructor;
public void run() {
while(true) {
String nextMessageToWrite = messageQueue.poll();
out.println(nextMessageToWrite);
}
}
public void send(String message) {
messageQueue.add(message);
}
}
This uses a blocking queue, which is a much better concurrency mechanism than a check-sleep loop. Then when the button is clicked, you can just have something like this:
public void actionPerformed() {
for ( WriteHandler handler : handlers ) {
handler.send("PING!");
}
}
Upvotes: 1