Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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:

enter image description here

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

like image 817
Caffeinated Avatar asked Mar 24 '13 21:03

Caffeinated


People also ask

What is heartbeat in Java?

The heartbeat mechanism monitors the connection between a manager and an agent and automates the cleanup procedure when the connection is lost. This enables both the manager and the agent to release resources that were allocated for maintaining the connection.

What is heartbeat in programming?

A heartbeat is a signal that is generated at regular intervals to indicate that something is working correctly. 2. Heartbeat is a program that runs specialized scripts automatically whenever a system is initialized or rebooted.

What is heartbeat connection?

A heartbeat is a type of a communication packet that is sent between nodes. Heartbeats are used to monitor the health of the nodes, networks and network interfaces, and to prevent cluster partitioning.


4 Answers

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

like image 110
mabn Avatar answered Oct 06 '22 05:10

mabn


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.

  1. 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.

like image 43
Bala Avatar answered Oct 06 '22 05:10

Bala


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)
{
}
like image 10
bvdb Avatar answered Oct 06 '22 04:10

bvdb


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.

like image 4
Cratylus Avatar answered Oct 06 '22 03:10

Cratylus