Monday, February 5, 2018

Can't send object via Object Output Stream from one http handler to another

Leave a Comment

So, in my app, I send the request from http server handler to another server. The thing is the second server is stuck on reading object. I was trying to figure out it myself but I can't see the problem. All streams are closed, maybe the response to the client is in the wrong place? I have no idea why is that..

This is my client:

public class ClientSimulator {      private Random random;     private static int clientCounter = 1;      public static void main(String[] args) throws Exception {         new ClientSimulator();         new ClientSimulator();         new ClientSimulator();     }      private ClientSimulator() {          this.random = new Random();         RuntimeMXBean rmb = ManagementFactory.getRuntimeMXBean();         long arrivalTime = rmb.getUptime();          System.out.println("thread no. " + clientCounter++ + " arrival time: " + arrivalTime);         try {             String myurl= "http://localhost:8080/sender";             String serverResponse = createClient(myurl);             System.out.println(serverResponse);         } catch (Exception e) {             e.printStackTrace();         }     }      private String createClient(String myurl) throws Exception {         URL url;         BufferedReader reader = null;         StringBuilder stringBuilder;          try {             //Standard HTTP connection             url = new URL(schedulerUrl);             HttpURLConnection connection = (HttpURLConnection) url.openConnection();             connection.setDoInput(true);             connection.setDoOutput(true);              int[] arr = {                     random.nextInt(10-1)+1,                     random.nextInt(10-1)+1,                     random.nextInt(10-1)+1,                     random.nextInt(10-1)+1,                     random.nextInt(10-1)+1,             };             Task t = new Task(arr);              ObjectOutputStream oos = new ObjectOutputStream(connection.getOutputStream());             oos.writeObject(t);             oos.close();              // read the output from the server             reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));             stringBuilder = new StringBuilder();             //print the response             String line = reader.readLine();             stringBuilder.append(line);              return stringBuilder.toString();         } catch (Exception e) {             e.printStackTrace();             throw e;         } finally {             if (reader != null) {                 try {                     reader.close();                 } catch (IOException ioe) {                     ioe.printStackTrace();                 }             }         }     }      private boolean getRandBool(){         return this.random.nextBoolean();     } } 

This is how I send the request from the main server to another server:

@Override     public void handle(HttpExchange httpExchange) throws IOException {          String template = "\nClient no. %s connected!";          //Getting task         Task t;         ObjectInputStream ois = new ObjectInputStream(httpExchange.getRequestBody());         try {             System.out.print("Recieved object:");             t = (Task) ois.readObject();             t.setDeadline(deadline);             t.setHard(isHard);             System.out.print(" not sorted array: ");             int[] arr = (int[]) t.getData();             for (int anArr : arr) {                 System.out.print(anArr + " ");             }             ois.close();             String response = "response for client no. " + clientCounter;            httpExchange.sendResponseHeaders(200, response.length());            OutputStream os = httpExchange.getResponseBody();            os.write(response.getBytes());            os.close();            clientCounter++;              HttpURLConnection test = (HttpURLConnection) new URL(fogServ1URL).openConnection();             test.setDoOutput(true);             System.out.println("test__1");             ObjectOutputStream stream = new ObjectOutputStream(test.getOutputStream());             stream.flush();             System.out.println("test__2");             stream.writeObject(t);             System.out.println("test__3");             stream.close();             System.out.println("test__4");             test.getResponseCode();             System.out.println("test__5"); //this doesn't print         } catch (ClassNotFoundException e) {             e.printStackTrace();         }     } } 

This is handler from the second server:

class RootHandler implements HttpHandler{ private static int clientCounter = 1;  @Override public void handle(HttpExchange exchange) throws IOException {        System.out.println("\nRoot handler; \n\tclient no. " + clientCounter++);      Task t;     ObjectInputStream ois = new ObjectInputStream(exchange.getRequestBody());     try {         System.out.println("Recieved object:"); //only this is on the console         t = (Task) ois.readObject();         ois.close();         System.out.println("Array not sorted:");         int[] arr = (int[]) t.getData();         for (int anArr : arr) {             System.out.print(anArr + " ");         }         TaskSolver.solve(t);         System.out.println("\nArray sorted!");         for (int anArr : (int[])t.getData()) {             System.out.print(anArr + " ");         }     } catch (ClassNotFoundException e) {         e.printStackTrace();     }      String response = "Server up!";     exchange.sendResponseHeaders(200, response.getBytes().length);     OutputStream os = exchange.getResponseBody();     os.write(response.getBytes());     os.close(); } } 

I don't get it because I send the Task from client to the main server in the same way and its working. I just can't read the output in the next servers. What am I doing wrong?

Btw. If someone is curious why I'm sending the same object to another server: I plan to create more servers, the main server will be sending requests to them depending on type/containing headers.

2 Answers

Answers 1

In Second server while reading the object there is some IOException occurred, since IOException in handle method of RootHandler class is passed to invoking method instead of handling it. So error like Internal Server Error response status is sent to client ( first server ).

Since there is exception in second server the test.getResponseCode() throws IOException since it is not handled in first server handle method

System.out.println("test__5");

is not invoked.

If you want to know what is happening catch IOException in handle method of the both server and print Stack trace.

Answers 2

Try following below sequence in your first server -

  1. Receive object by reading the InputStream
  2. Connect with the second server.
  3. Send object by writing on OutputStream of second server.
  4. Get the response from second server
  5. Send response to client by writing on OutputStream of first server.

The reason behind current behavior is related to closing of Exchange. As per the documentation -

Exchanges are terminated when both the request InputStream and response OutputStream are closed.

Currently, in your first server code, you are writing the response on OutputStream and then closing it. After that, your first server start communicating with second server.

When first server sent request to second server and wait for the response, at the time, underlying HttpExchange gets closed, thus connection and associated thread are released. Till this time, second server hasn't read the request.

In this situation, some IOException must occur in second server for indicating the error or second server will keep waiting for reading the InputStream and eventually get timeout.

Closing of Exchange and releasing of associated thread is not immediate step after closing OutputStream, but it can terminate anytime and subsequent code lines are not guaranteed to be executed. In your case, connection terminated while waiting for the response from second server but it can terminate before that also.

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment