I need a way to automatically close the server program which runs by using some sort of timer. Till now this is what I got
long start = System.currentTimeMillis();
long end = start + 10 * 1000; // 60 seconds * 1000 ms/sec
while (System.currentTimeMillis() < end) {
Socket connectionSocket = welcomeSocket.accept();
BufferedReader inFromClient = new BufferedReader(
new InputStreamReader(connectionSocket.getInputStream()));
DataOutputStream outToClient = new DataOutputStream(
connectionSocket.getOutputStream());
clientSentence = inFromClient.readLine();
System.out.println("Received: " + clientSentence);
capitalizedSentence = clientSentence.toUpperCase() + '\n';
outToClient.writeBytes(capitalizedSentence);
count = count + 1;
}
welcomeSocket.close();
Is this possible? Please help and don't down vote. I'm kinda a noob regarding client- server in Java.
You can use setSoTimeout for that.
Typically, you'll set that with some value like 100 ms, enter a loop and call accept. When the timeout exception is thrown you'll check to see if its ok to exit or not and either fall out of the loop or keep going.
Then make sure you clean up the socket when you're done.
Run the code you have there in a Thread (named server in the code below), and then start another Thread like this to do an interrupt when you want to exit:
Thread server = {the one you have};
Thread timeout = new Thread() {
public void run() {
long end = start + 10 * 1000;
try {
Thread.sleep(end);
} catch (InterruptedException e) {
//handle this
}
server.interrupt();
}
}
timeout.start();
The socket.accept will now throw InterruptedException and bypass all your other code.
I am not sure if you are okay with Threads. Would still recommend you to have a look at the Timer class.
You can create a Timer, which created a thread to close down your server. You can make your connection as a final variable and then use synchronised access to it to close it once Timer thread kicks in.
Related
Is it possible to set timer for user's input? Wait 10 seconds - do next operation and etc.
I mean for example
//wait several seconds{
String s = new BufferedReader(new InputStreamReader(System.in)).readLine();
//wait server seconds}
//next operation and etc.
A slightly easier way to do this than Benjamin Cox's answer would be to do something like
int x = 2; // wait 2 seconds at most
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
long startTime = System.currentTimeMillis();
while ((System.currentTimeMillis() - startTime) < x * 1000
&& !in.ready()) {
}
if (in.ready()) {
System.out.println("You entered: " + in.readLine());
} else {
System.out.println("You did not enter data");
}
This will, however consume more resources than his solution.
Not right out of the box, no. Normally the Reader only breaks out of a read() call when another thread closes the underlying stream, or you reach the end of the input.
Since read() is not all that interruptible this becomes a bit of a concurrent programming problem. The thread that knows about the timeout will need to be able to interrupt the thread that's trying to read the input.
Essentially, the reading thread will have to poll the Reader's ready() method, rather than getting locked in read() when there's nothing to read. If you wrap this polling and waiting operation in a java.util.concurrent.Future, then you call the Future's get() method with a timeout.
This article goes into some detail: http://www.javaspecialists.eu/archive/Issue153.html
BufferedReader inputInt = new BufferedReader(new InputStreamReader(System.in));
Robot enterKey = new Robot();
TimerTask task = new TimerTask() {
public void run() {
enterKey.keyPress(KeyEvent.VK_ENTER);
}
};
Timer timer = new Timer();
timer.schedule(task, 30 * 1000);
userInputanswer = inputInt.read();
timer.cancel();
Alright, so I changed it to this, I closed the socket and modified the loop
Socket clientSocket = serverSocket.accept();
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(),true);
connectedClients++;
if (connectedClients < maxPlayers) {MortgageRunnable m = new MortgageRunnable(clientSocket);
System.out.println("New player has connected!");
new Thread(m).start();}
else{out.println("Connection unsuccessful, Max players connected");clientSocket.close();}
the only thing left is it doesn't send the message to the client ("Connection unsuccessful, Max players connected") it just disconnects.
How can I send the message to the client?
You seem to be leaving sockets open when rejecting players.
The logic should be:
while (true) {
socket = accept()
if (too many players) {
send "too many players" message
close socket
} else {
increment player counter
new Thread(new MortgageRunnable(socket)).start()
}
}
Also, when a player leaves / thread exits, you should decrement the counter.
Finally, creating a new PrintWriter each time you send a message is a bad idea.
Your code continues to accept new incoming connections because the while loop does not exit. To fix that, once you hit the maximum allowed connections, you need to get out of the while loop. Here is your code (without the dangling try statement) with one extra line after printing "Max players connected". Once you reach maxPlayers total number of connections, this will stop accepting new connections.
while (true) {
Socket clientSocket = serverSocket.accept();
MortgageRunnable m = new MortgageRunnable(clientSocket);
System.out.println("New player has connected!");
if (!(connectedClients == maxPlayers)) {
new Thread(m).start();
connectedClients++;
} else {
m.displayMessage("Max players connected");
break; // get out of the while loop
}
}
Another small suggestion: instead of checking if (!(connectedClients == maxPlayers) {...}, change it to something like if (connectedClients < maxPlayers) {...} – simpler logic, the code is more readable, easier to reason about.
EDIT: here's a variation. This time, I've moved most of the work into a new acceptNewClient() method. Also, the if statement is reworked to eject once connectedClients < maxClients is no longer true.
public void listenForClientConnections() {
while (true) {
MortgageRunnable m = acceptNewClient();
connectedClients++;
boolean maxClientsReached = !(connectedClients < maxClients);
if (maxClientsReached) {
m.displayMessage("Max clients connected");
break; // exit "while" loop, no more connections will be accepted
}
}
}
private MortgageRunnable acceptNewClient() {
Socket clientSocket = serverSocket.accept();
MortgageRunnable m = new MortgageRunnable(clientSocket);
System.out.println("New client has connected!");
new Thread(m).start();
return m;
}
Is it possible to set timer for user's input? Wait 10 seconds - do next operation and etc.
I mean for example
//wait several seconds{
String s = new BufferedReader(new InputStreamReader(System.in)).readLine();
//wait server seconds}
//next operation and etc.
A slightly easier way to do this than Benjamin Cox's answer would be to do something like
int x = 2; // wait 2 seconds at most
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
long startTime = System.currentTimeMillis();
while ((System.currentTimeMillis() - startTime) < x * 1000
&& !in.ready()) {
}
if (in.ready()) {
System.out.println("You entered: " + in.readLine());
} else {
System.out.println("You did not enter data");
}
This will, however consume more resources than his solution.
Not right out of the box, no. Normally the Reader only breaks out of a read() call when another thread closes the underlying stream, or you reach the end of the input.
Since read() is not all that interruptible this becomes a bit of a concurrent programming problem. The thread that knows about the timeout will need to be able to interrupt the thread that's trying to read the input.
Essentially, the reading thread will have to poll the Reader's ready() method, rather than getting locked in read() when there's nothing to read. If you wrap this polling and waiting operation in a java.util.concurrent.Future, then you call the Future's get() method with a timeout.
This article goes into some detail: http://www.javaspecialists.eu/archive/Issue153.html
BufferedReader inputInt = new BufferedReader(new InputStreamReader(System.in));
Robot enterKey = new Robot();
TimerTask task = new TimerTask() {
public void run() {
enterKey.keyPress(KeyEvent.VK_ENTER);
}
};
Timer timer = new Timer();
timer.schedule(task, 30 * 1000);
userInputanswer = inputInt.read();
timer.cancel();
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');
}
Is it possible to set timer for user's input? Wait 10 seconds - do next operation and etc.
I mean for example
//wait several seconds{
String s = new BufferedReader(new InputStreamReader(System.in)).readLine();
//wait server seconds}
//next operation and etc.
A slightly easier way to do this than Benjamin Cox's answer would be to do something like
int x = 2; // wait 2 seconds at most
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
long startTime = System.currentTimeMillis();
while ((System.currentTimeMillis() - startTime) < x * 1000
&& !in.ready()) {
}
if (in.ready()) {
System.out.println("You entered: " + in.readLine());
} else {
System.out.println("You did not enter data");
}
This will, however consume more resources than his solution.
Not right out of the box, no. Normally the Reader only breaks out of a read() call when another thread closes the underlying stream, or you reach the end of the input.
Since read() is not all that interruptible this becomes a bit of a concurrent programming problem. The thread that knows about the timeout will need to be able to interrupt the thread that's trying to read the input.
Essentially, the reading thread will have to poll the Reader's ready() method, rather than getting locked in read() when there's nothing to read. If you wrap this polling and waiting operation in a java.util.concurrent.Future, then you call the Future's get() method with a timeout.
This article goes into some detail: http://www.javaspecialists.eu/archive/Issue153.html
BufferedReader inputInt = new BufferedReader(new InputStreamReader(System.in));
Robot enterKey = new Robot();
TimerTask task = new TimerTask() {
public void run() {
enterKey.keyPress(KeyEvent.VK_ENTER);
}
};
Timer timer = new Timer();
timer.schedule(task, 30 * 1000);
userInputanswer = inputInt.read();
timer.cancel();