Link to home
Start Free TrialLog in
Avatar of java63
java63

asked on

Socket Connection in the presence of network faults

Hi there

My task is to deal with network crashes using socket connection. I am simulating a transfer funds between two accounts that are modelled as simple integer.  This is only console based application. The possible problems are:

a). Process A cannot establish a connection with process B. The system display message cannot locate server.(Done)

b). Process A send request to process B. If timer expires before acknowledgement is sent back. Message is re-sent again, max 4 times and than go back to point a. (would be nice to have a loop going 4 times over – don’t know how to do it). I can manually reconnect a few times but it would be better to have a loop.

c.) (Most difficult to do it) Process A sent a request to process B. B receives it, execute it ( or only receives no execute). Timer is out (which indicate server has crashed). No replay sends for process A. We don’t want to transfer funds twice.

Possible solutions for c:
A send a request with attached additional bit 0 in the message header to indicate original request or 1 indicate re-transmission request.
B logs a request.
If B crashes it then check a previous status against the current one (compare added bits).
If status is 0 it means that it is original request, if status is 1 this is re-transmission request.
Process B will refuse to carry out any request a second time (to avoid mistake)


I think the server should save each request to file so it could then compare it with retransmitted one.  
My application can pass serialized object as an Integer from one machine to another and back. I know how to save serialized object using I/O streams in a single process and read it back. What I don’t know is to how to combine these two so I can send a request and then save it to file at the same time. Maybe you have different suggestions.
This is my code.


import java.io.*;
import java.net.*;

public class AccountServer extends Thread {
       private ServerSocket dateServer;

      /**
       * @param args
       */
      public static void main(String[] args) throws Exception {
            // TODO Auto-generated method stub
             new AccountServer();

      }
      public AccountServer() throws Exception {
           dateServer = new ServerSocket(4000);
           System.out.println("Server listening on port 4000.");
           this.start();
         }

         public void run() {
           while(true) {
             try {
              System.out.println("Waiting for connections.");
              Socket client = dateServer.accept();
              System.out.println("Accepted a connection from: "+
      client.getInetAddress());
              Connect c = new Connect(client);
             } catch(Exception e) {}
           }
         }
      }

      class Connect extends Thread {
         private Socket client = null;
         private ObjectInputStream ois = null;
         private ObjectOutputStream oos = null;
          
         public Connect() {}

         public Connect(Socket clientSocket) {
           client = clientSocket;
           try {
            ois = new ObjectInputStream(client.getInputStream());
            oos = new ObjectOutputStream(client.getOutputStream());
           } catch(Exception e1) {
               try {
                  client.close();
               }catch(Exception e) {
                 System.out.println(e.getMessage());
               }
               return;
           }
           this.start();
         }

        
         public void run() {
               
               UserInfo user1 = null;
               
               try {
                    
                       user1 = (UserInfo) ois.readObject();
                       int amount = user1.getAmount();
                     
                     
                     // ship the object to the client
                     UserInfo user = new UserInfo(amount);
                     user.setAmount(amount);
                     oos.writeObject(user);
                     oos.flush();
                     // close connections
                     ois.close();
                     oos.close();
                     client.close();
                  } catch(Exception e) {}      
               }
            }

----------------------------------------------------------------------------------------------------

import java.io.*;
import java.net.*;

public class AccountClient {
   public static void main(String argv[]) {
      ObjectOutputStream oos = null;
      ObjectInputStream ois = null;
     
     
      // int value
      int amount = 100;
     
      try {
        // open a socket connection
        Socket socket = new Socket("localhost", 4000);
       
        // open I/O streams for objects
        oos = new ObjectOutputStream(socket.getOutputStream());
        ois = new ObjectInputStream(socket.getInputStream());
       
        // create serialized object
        UserInfo user1 = new UserInfo(100);
       
        // write the objects to the server
        oos.writeObject(user1);
        oos.flush();
       
        // read an object from the server
        user1 = (UserInfo) ois.readObject();
        System.out.print("The transfer is completed. The amount of £"+amount+" was received");
       
       
        oos.close();
        ois.close();
      } catch(Exception e) {
        System.out.println(e.getMessage());
      }
   }
}
Avatar of Kelvin_King
Kelvin_King
Flag of Singapore image

That sounds like a good method.

here's how you can serialize an object to file:

http://javaalmanac.com/egs/java.io/SerializeObj.html,

so before you do any processing at the server side, serialize the Object first.
Avatar of java63
java63

ASKER

I said in my question above

<<I know how to save serialized object using I/O streams in a single process and read it back. What I don’t know is to how to combine these two to keep communication alive even that the network is crashing...>>  
I still want to give you those points but you have to help me more, as this question have not being answered yet.

The good point you have made is a suggestion to use it before I do any processing at the server side (I could not get it right because I tried to do it after client and server exchange messages).
However, as far as I concern there is still problem. In order to carry on communication between client-server I have to run the server first, which means the object is automatically save to the hard drive before client is even running. Am I understanding is right?  I think when I run client too, the message then should be save to the file on the server and then retrieve to check if necessary. Therefore before I posted the question I tried to perform saving after client established the connection with the server but I was not sure where to insert the statement. This is the change I made

public static void main(String[] args) throws Exception {
            // TODO Auto-generated method stub
             new AccountServer();
             
             try
             {
                   // save amount to file
                   ObjectOutputStream oos = new ObjectOutputStream(new
                               FileOutputStream("C:\\Documents and Settings\\Dariusz\\My Documents\\Distributed Systems\\amount1.out"));
                   UserInfo user1 = new UserInfo(100);
                   oos.writeObject(user1);
                   oos.flush();
                   oos.close();
                  
                   // retrieve all records from a file
                   ObjectInputStream ois = new ObjectInputStream(new
                               FileInputStream("C:\\Documents and Settings\\Dariusz\\My Documents\\Distributed Systems\\amount1.out"));
                   UserInfo user2 = (UserInfo) ois.readObject();
                   //invoke a method on the constructed object
                      //user2.printInfo();
                      ois.close();
                      
                   }
             catch (IOException e){
                  
             }


      }
      public AccountServer() throws Exception {
           dateServer = new ServerSocket(4000);
           System.out.println("Server listening on port 4000.");
           this.start();
         }


I can treat this as a separate question ( but their both have connection is it?)
Should I have read and write to file on both sides(I mean client-server). The problem is before I run client the file is save on the server and read at the same time and then is read again when I run client connecting to the server. This has to be sorted out. Please tried to run by design then you will see.
I feel there is no issue to being with. Let's say a client sends a message to the server, attach a unique sequence number to the request, eg: "Request 1234: Transfer 100 from account A to account B".

When the server receives this request, serialize it, and save it to disk. That's all it needs to do.

Meanwhile, the client simply waits for an acknolegement from the server.

If there is no reply by a certain amount of time due to network problems, or server crash etc, then the client resends the request with the same sequence number.

On the server side, assuming it crashed and has now reboot, it will first look through it's log to check for any transactions that it received but didn't process, and process them accordingly. At this point, I'll make a suggestion.

The server maintains 2 log files, one for requests received, and one for requests processed. The moment the server receives a request, it writes it to the received log. It then continues to process it, as soon as that's done, the request is moved to the processed log.

So this way, the client doesn't need to maintain a log file, only the server does. Should the server crash, after it recovers it processes all the requests in the received log, and if it should receive a request from the client, it will check it's processed log if it is a duplicate request, if it is it will send back an acknoledgement.

Avatar of java63

ASKER

I am allocating 500 points to Kelvin King but still need further help.
I like this idea of maintaining 2 log files, the only question is how to do this in terms of coding, I would appreciate if you could help.
What my application does so far, client established a connection with the server, server accepts a connection form the client, saved a file to disk to a folder called Received Log and then send acknowledgment back to the client.
What I need to design is :
After an acknowledgment is send back to the client the file from Received log is moved to Process log (when you say moved, is this means it is not anymore in folder Received Log? Is this right?) . I understand that I simply save this file again, but to different folder called  Process Log. When I reboot the server I should be able to read file from both Received and Processed logs. How to do it?  This is my code:

import java.io.*;
import java.net.*;

public class AccountClient {
   public static void main(String argv[]) {
      ObjectOutputStream oos = null;
      ObjectInputStream ois = null;
     
     
      // int value
      int amount = 100;
     
      try {
        // open a socket connection
        Socket socket = new Socket("localhost", 4000);
       //socket.connect(new InetSocketAddress("localhost",4000),timeout);
       
        // open I/O streams for objects
        oos = new ObjectOutputStream(socket.getOutputStream());
        ois = new ObjectInputStream(socket.getInputStream());
       
        // create serialized object
        UserInfo user1 = new UserInfo(100);
       
        // write the objects to the server
        oos.writeObject(user1);
        oos.flush();
       
        // read an object from the server
        user1 = (UserInfo) ois.readObject();
        System.out.print("Request 1A: Transfer £"+amount+" from account A to account B");
       
       
        oos.close();
        ois.close();
      } catch(Exception e) {
        System.out.println(e.getMessage());
      }
   }
}
---------------------------------------------------------------------------

import java.io.*;
import java.net.*;



public class AccountServer extends Thread {
       private ServerSocket dateServer;

      /**
       * @param args
       */
      public static void main(String[] args) throws Exception {
            // TODO Auto-generated method stub
             new AccountServer();
             
             
                  
             //}


      }
      public AccountServer() throws Exception {
           dateServer = new ServerSocket(4000);
           //dateServer.setSoTimeout(100000); // timeout after 10 seconds(not employed yet
           System.out.println("Server listening on port 4000.");
           this.start();
         }

         public void run() {
           while(true) {
             try {
              System.out.println("Waiting for connections.");
              Socket client = dateServer.accept();
              System.out.println("Accepted a connection from: "+
      client.getInetAddress());
              Connect c = new Connect(client);
             } catch(Exception e) {}
           }
         }
      }

      class Connect extends Thread {
         private Socket client = null;
         private ObjectInputStream ois = null;
         private ObjectOutputStream oos = null;
          
         public Connect() {}

         public Connect(Socket clientSocket) {
           client = clientSocket;
           try {
            ois = new ObjectInputStream(client.getInputStream());
            oos = new ObjectOutputStream(client.getOutputStream());
           } catch(Exception e1) {
               try {
                  client.close();
               }catch(Exception e) {
                 System.out.println(e.getMessage());
               }
               return;
           }
           this.start();
         }

        
         public void run() {
               
               UserInfo user1 = null;
               
               
               
               try {
                    
                       user1 = (UserInfo) ois.readObject();
                       int amount = user1.getAmount();
                     
                     
                     // ship the object to the client
                     UserInfo user = new UserInfo(amount);
                     user.setAmount(amount);
                     oos.writeObject(user);
                     oos.flush();
                     // close connections
                     ois.close();
                     oos.close();
                     client.close();
                  }catch(Exception e) {}      
               //}
         try
             {
                   // save request to file called ReceivedLog
                   ObjectOutputStream oos = new ObjectOutputStream(new
                               FileOutputStream("C:\\Documents and Settings\\Dariusz\\My Documents\\ReceivedLog\\amount1.out"));
                   UserInfo user2 = new UserInfo(100);
                   oos.writeObject(user2);
                   oos.flush();
                   oos.close();
                  
                   // retrieve all records from a file
                   ObjectInputStream ois = new ObjectInputStream(new
                               FileInputStream("C:\\Documents and Settings\\Dariusz\\My Documents\\ReceivedLog\\amount1.out"));
                   UserInfo user11 = (UserInfo) ois.readObject();
                   //invoke a method on the constructed object
                      user11.printInfo();
                      ois.close();
                      
             }
             catch (IOException e)
             {
            e.printStackTrace();
             } catch (ClassNotFoundException e) {
                  e.printStackTrace();
            }
            }
             
      }
      


Actually, the server should first process the request, and then send acknoledgement back to client, and then move the request from the received log to the processed log.

You then write the request to the processed log file,
then remove the request from the received log.

To do that, you'll probably have to over write the entire contents of the file, meaning read in all the contents of the received log, remove that particular request, and write back the rest of the requests.
Avatar of java63

ASKER

Would you try to add some code. I like this idea in general, however don't you think it sounds a bit complicated  in terms of implementation.
well, sounds complicated is one thing. But as programmers we know what we must do and find the most efficient way to get it done.

What part are you having difficulties in particular?

The transfering of log entreis ?
Avatar of java63

ASKER

I posted all my code, and difficult part at the moment I how to move that log from received log to processed log, so as soon as client send a message I can store the value of that message in received log but then after acknowledgment is sent back that file should be move to processes log and stored there so it then can be check(read). I do not know how to move that file to process log.
>> I do not know how to move that file to process log.

you don't move the file any where. Rather you move the contents from that file, to the other file. It's quite simple really.

Read from the received log.
Identify which request should be moved.
write that request to the processed log.
OVER WRITE the received log - minus the processed request.

It's basically doing a cut and paste. but only you have to use java to do it.

So i really don't think it's that complicated. Sure it'll take a few more lines of code, but not much of a problem.
Avatar of java63

ASKER

I am getting a bit confused about it. I added an additional statement which writes the file again but just to different folder called Processed Log. I put  this statement straight after client request is read from received log and then printed out. I have notice that when I tried to deleted a file in received log I could do it, but I could not delete a file in folder processed log, when the server and client was still running. What this means? Is this correct ?. What I really need to solve out is when client send a request ,  lest say server crash after writing a request to received log. After rebooting I need to read a file from received log and then from processed log to see if that request was already processed or not and then act accordingly. Is this right or not?

try
             {
                   // save request to file called ReceivedLog
                   ObjectOutputStream oos = new ObjectOutputStream(new
                               FileOutputStream("C:\\Documents and Settings\\Dariusz\\My Documents\\ReceivedLog\\amount.out"));
                   UserInfo user2 = new UserInfo(100);
                   oos.writeObject(user2);
                   oos.flush();
                   oos.close();
                  
                   // retrieve all records from a file
                   ObjectInputStream ois = new ObjectInputStream(new
                               FileInputStream("C:\\Documents and Settings\\Dariusz\\My Documents\\ReceivedLog\\amount.out"));
                   UserInfo user11 = (UserInfo) ois.readObject();
                   //invoke a method on the constructed object
                      user11.printInfo();
                      ObjectOutputStream oos1 = new ObjectOutputStream(new
                                     FileOutputStream("C:\\Documents and Settings\\Dariusz\\My Documents\\ProcessedLog\\amount3.out"));
                      UserInfo user3 = new UserInfo(100);
                        oos1.writeObject(user3);
                        oos1.flush();
                      
                      
                      ois.close();
                      
             }
             catch (IOException e)
             {
            e.printStackTrace();
             } catch (ClassNotFoundException e) {
                  e.printStackTrace();
            }
            }
             
      }
ASKER CERTIFIED SOLUTION
Avatar of Kelvin_King
Kelvin_King
Flag of Singapore image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of java63

ASKER

Hello I need a fast help only with the syntax 500 points.
My application communicates over socket connection. It sends a String message + integer value from process A(Client) to process B(Server). I am dealing with fault tolerance.

There are some points in my application that do not work properly. What works properly is this:

1.      I send a message and get response back.
2.      When Server is down, client is trying to re-connect for 4 times using loop and finally log off.

3.      When a message is sent from client to server after client is connected lack of acknowledgement will force client to re-connect for a few times. ( I do this by putting server to sleep after client connect to the server, but before acknowledgement is sent back)

This part does not work 100% correct. After disabling sleep functionality on the server message is passed to the server (which is correct) but loop still simulates that is trying to reconnect, which is wrong. There is a mistake in a second loop in a client code.


4.      Message sent to the server is saved in 2 folders Received log and Processed log.


When the server receives this request, serialize it, and save it to above folders. The moment the server receives a request, it writes it to the received log. It then continues to process it, as soon as that's done, the request is then remove from the received log and moved to the processed log.

(I put some code but is doesn’t work). All is does is save the message to 2 folders and that’s it.

This is all my code.

package account;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      package account;

import java.io.Serializable;


public class UserInfo implements Serializable {
      static String TimeStamp;
   /**
       *
       */
       private static final long serialVersionUID = 1L;
       int amount = 0;
      

   public UserInfo(int amount) {
      this.amount = amount;
   }
   
   public void setAmount(int amount){
         this.amount = amount;
   }
   
   public int getAmount() {
            return 0;
      }
   
   public void printInfo() {
         TimeStamp = new java.util.Date().toString();
         System.out.println(TimeStamp + " Transfer of £"+amount+" from account A to account B \n<<Transferr Done!>>" );
   }


}
----------------------------------------------

package account;

import java.io.*;
import java.net.*;

public class AccountClient {
       Socket socket = null;
       ObjectOutputStream oos = null;
     ObjectInputStream ois = null;
     //SocketAddress socketAdd;
     int amount = 100;
     
      public static void main(String argv[]) throws IOException, InterruptedException, ClassNotFoundException {
        AccountClient client = new AccountClient();
        client.tryToConnect();
        
   }
            
        
        public void tryToConnect () throws IOException, InterruptedException,ClassNotFoundException {
       boolean reply = true;
       boolean resend = false;
       int i = 0;
       while(true){
             if(i<4){
                   try{
                         System.out.println("Connecting to the server...............");
                          //open a socket connection
                        SocketAddress socketAdd = new InetSocketAddress("localhost", 4000);
                        socket = new Socket();
                        if(resend){
                              socket.setSoTimeout(10000);// time out after 10 seconds
                              
                        }
                        socket.connect(socketAdd);
                        if( socket.isConnected()){
                              break;
                        }
                   }catch(UnknownHostException error){
                         i++;
                         resend = true;
                   }catch(IOException ex){
                         i++;
                         resend = true;
                   }
             }else{
                   reply = false;
                   break;
             }// exit from the loop after reconnecting for 4 times
       }//end of loop
       if(reply){
             waitForAnswer();
       }else{
             System.out.println("Server is not available at this time");
             reply = false;
       }
       }

            
               
       

        
       
       
                                                                                   
       public void waitForAnswer() throws IOException, InterruptedException, ClassNotFoundException{
              int i = 0;
              boolean reply = true;
            boolean resend = false;
            while(true){
                 if(i<2){
                       try{
                             //open I/O streams for objects
                             oos = new ObjectOutputStream(socket.getOutputStream());
                           ois = new ObjectInputStream(socket.getInputStream());
                       //}
                        //catch(Exception e){}  
                         
                           //while(true){
                           //if(reply){
                           //if(i<4){
                                 //try{
                           
                                 //socket.setSoTimeout(6000);
                                 System.out.println("<< connection sucesfull >>");
                                 System.out.println(+amount+ " is being sent to account B: " + "....lack of acknowledgement");
                                 socket.setSoTimeout(6000);
                                 break;
                                
                                 }catch(IOException ex1){
                                    
                                   i++;
                                   resend = true;
                                   System.out.println("Attempt: " + i + "\t Re-sending Request To Account B");
                                 }
                           
                                       }else{
                                       reply = false;
                                       System.out.println("Server may be down");
                                       break;
                                       }
                           }
                           
                       }
}
                
-----------------------------------------------
                    
package account;

import java.io.*;
import java.net.*;
import java.nio.channels.FileChannel;



public class AccountServer extends Thread {
      private ServerSocket dateServer;
     

     /**
      * @param args
      */
     public static void main(String[] args) throws Exception {
          // TODO Auto-generated method stub
           new AccountServer();
           
           
               
           //}


     }
     public AccountServer() throws Exception {
          dateServer = new ServerSocket(4000);
          System.out.println("Server listening on port 4000.");
          this.start();
        }

        public void run() {
          while(true) {
            try {
             System.out.println("Waiting for connections.");
             Socket client = dateServer.accept();
             //client.setSoTimeout(10000); // timeout after 10 seconds(not employed yet
             System.out.println("Accepted a connection from: "+
     client.getInetAddress());
             Connect c = new Connect(client);
            } catch(Exception e) {}
          }
        }
     }

     class Connect extends Thread {
        private Socket client = null;
        private ObjectInputStream ois = null;
        private ObjectOutputStream oos = null;
         
        public Connect() {}

        public Connect(Socket clientSocket) throws SocketException {
          client = clientSocket;
         
         
          try {
           ois = new ObjectInputStream(client.getInputStream());
           oos = new ObjectOutputStream(client.getOutputStream());
           //Thread.sleep(15000);
           
           
          } catch(Exception e1) {
              try {
                 client.close();
              }catch(Exception e) {
                   
                  System.out.println(e.getMessage());
              }
              return;
          }
          this.start();
        }

       
        public void run() {
             
             UserInfo user1 = null;
             
             
             
             try {
                 
                    user1 = (UserInfo) ois.readObject();
                    int amount = user1.getAmount();
                   
                   
                  //ship the object to the client
                   UserInfo user = new UserInfo(amount);
                   //user.setAmount(amount);
                   oos.writeObject(user);
                   oos.flush();
                   // close connections
                   ois.close();
                   oos.close();
                   client.close();
                }catch(Exception e) {
                      
                }      
             
        try
           {
              
              
              //save request to file called ReceivedLog
              ObjectOutputStream oos = new ObjectOutputStream(new
                      FileOutputStream("C:\\Documents and Settings\\Dariusz\\My Documents\\ReceivedLog\\amount.txt"));
            UserInfo user2 = new UserInfo(100);
            oos.writeObject(user2);
            oos.flush();
            oos.close();
           

            try{
           
            File file = new File("C:\\Documents and Settings\\Dariusz\\My Documents\\ReceivedLog\\amount.txt");
            ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
            // Deserialize the object
            UserInfo user11 = (UserInfo) ois.readObject();
            user11.printInfo();
           
          //Create channel on the source
            FileChannel srcChannel = new FileInputStream("C:\\Documents and Settings\\Dariusz\\My Documents\\ReceivedLog\\amount.txt").getChannel();
          //Create channel on the destination
            FileChannel dstChannel = new FileOutputStream("C:\\Documents and Settings\\Dariusz\\My Documents\\ProcessedLog\\amount.txt").getChannel();
          //Copy file contents from source to destination
            dstChannel.transferFrom(srcChannel, 0, srcChannel.size());
          //Close the channels
            srcChannel.close();
            dstChannel.close();
            } catch (IOException e) {
            }


           
           

           
            // retrieve all records from a file
            //ObjectInputStream ois = new ObjectInputStream(new
                      //FileInputStream("C:\\Documents and Settings\\Dariusz\\My Documents\\ReceivedLog\\amount.txt"));
            //UserInfo user11 = (UserInfo) ois.readObject();
            //invoke a method on the constructed object
            //user11.printInfo();
               
            //save request to file called ProcessedLog
            ObjectOutputStream oos1 = new ObjectOutputStream(new
                      FileOutputStream("C:\\Documents and Settings\\Dariusz\\My Documents\\ProcessedLog\\amount.txt"));
               UserInfo user3 = new UserInfo(100);
               oos1.writeObject(user3);
               oos1.flush();
               ois.close();
               
             //delete file
               boolean success = (new File("C:\\Documents and Settings\\Dariusz\\My Documents\\ReceivedLog\\amount.txt")).delete();
               if (!success) {
                   // Deletion failed
               }

               
       }
       catch (IOException e)
       {
      e.printStackTrace();
       } catch (ClassNotFoundException e) {
           e.printStackTrace();
      }
      }
       
 }