1

It's my first time working with sockets, in order to get a better understanding of what's going on I decided to build a client server chat application which can support several users.

At first, I used DataInputStream / DataOutputStream to communicate and everything works well. But I would like to switch to an ObjectStream and that's where the problem occurs. Once I replace all the DataInputStream / DataOutputStream by ObjectInputStream / ObjectOutputStream, I'm no longer able to print the retrieved data.

This is the code that I used before, which works (DataStream) :

SERVER:

       try {
            DataInputStream in = new DataInputStream(socket.getInputStream());
            DataOutputStream out = new DataOutputStream(socket.getOutputStream());

            out.writeUTF("HI FROM SERVER");
            while (!socket.isClosed()) {
                try {
                    if (in.available() > 0) {
                        String input = in.readUTF();
                        for (ClientThread thatClient : server.getClients()){
                            DataOutputStream outputParticularClient = new DataOutputStream(thatClient.getSocket().getOutputStream());
                            outputParticularClient.writeUTF(input + " GOT FROM SERVER");
                        }
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

CLIENT:

try {
    socket = new Socket("localhost", portNumber);


    DataInputStream in = new DataInputStream(socket.getInputStream());
    new Thread(()->{
        while(!socket.isClosed()){
            try {
                if (in.available() > 0){
                    String input = in.readUTF();
                    System.out.println(getUserName() + " > " + input);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }).start();
} catch (IOException e) {
    e.printStackTrace();
}

And this is how I tried to perform the same idea with ObjectStream :

SERVER:

try {
    ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
    ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());

    while (!socket.isClosed()) {
        try {
            if (in.available() > 0) {
                Message input;
                try {
                    input = (Message)in.readObject();
                    if (input.equals(null)){
                        System.err.println("SERVER RETRIEVED NULL OBJECT");
                    }
                    for (ClientThread thatClient : server.getClients()){
                        ObjectOutputStream outputParticularClient = new ObjectOutputStream(thatClient.getSocket().getOutputStream());
                        outputParticularClient.writeObject(input);
                    }
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
} catch (IOException e) {
    e.printStackTrace();
}

CLIENT:

try {
            socket = new Socket(getHost(), portNumber);

            ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
            new Thread(()->{
                while(!socket.isClosed()){
                    try {
                        if (in.available() > 0){
                            Message input = null;
                            try {
                                input = (Message)in.readObject();
                                if (input.equals(null)){
                                    System.err.println("CLIENT RETRIEVED NULL OBJECT");
                                }
                                System.out.println("CLIENT " + input.toString());
                            } catch (ClassNotFoundException e) {
                                e.printStackTrace();
                            }
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        } catch (IOException e) {
            e.printStackTrace();
        }

I feel like it has something to do with this if statement if (in.available() > 0) but I cannot say precisely what's going on.

14
  • try adding flush/close after outputParticularClient.writeObject(input); (the stream is never closed) Commented Jun 7, 2019 at 11:46
  • I've tried that, but is still not working. The reason why I leave them open is because they are suppose to communicate as long as the application runs. Once it's closed the listeners are closed as well. Commented Jun 7, 2019 at 11:51
  • 2
    'I'm no longer able to print the retrieved data' is not a problem description. Your use of available() is pointless. Commented Jun 7, 2019 at 12:14
  • 1
    StreamCorrupted has nothing to do with the use of available(). You must be doing something else wrong. Still, flush is most likely required for the data to be sent (else, flush occurs only when the buffers are full or when the streams are closed). Commented Jun 7, 2019 at 12:42
  • 1
    As @user207421 said, the use of available is pointless. The StreamCorruptedException should be caused by re-creating new ObjectOutputStreams as described in the answer to this question. Commented Jun 7, 2019 at 15:25

1 Answer 1

4

available() doesn't do what you may think it does and it is almost never useful in production code (and that's particularly true for ObjectInputStream). The reason you don't receive any data is in fact that in.available() always returns 0 as you already suspected.

As noted in the comments, the StreamCorruptedException is caused by writing to an existing ObjectInputStream that has already been written to using another instance of ObjectOutputStream. Cf. the answer StreamCorruptedException: invalid type code: AC for further explanation.

Here is some quick & dirty example code that has a server echoing the messages from two clients. It's not clean but it may give you an idea how to approach your problem:

public class SO56493162 {

   private static final class Message implements Serializable {
      private static final long serialVersionUID = 1L;
      private static int cnt = 0;
      private final int id;

      public Message(int id) {
         ++cnt;
         this.id = id;
      }

      public String toString() {
         return "Msg from " + id + " : " + cnt;
      }
   }

   private static final class Client implements Runnable {
      private InetSocketAddress addr = null;
      private int id = -1;

      Client(InetSocketAddress addr, int id) {
         this.addr = addr;
         this.id = id;
      }

      public void run() {
         int timeout = 3000;
         Socket s = null;
         try {
            s = new Socket();
            s.connect(addr, timeout);
            ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream());
            ObjectInputStream ois = new ObjectInputStream(s.getInputStream());
            System.out.println("Client " + id + " connected");
            while (true) {
               Thread.sleep(new Random().nextInt(2000));
               Message hello = new Message(id);
               oos.writeObject(hello);
               oos.flush();
               Message reply = (Message) ois.readObject();
               System.out.println("Reply: " + reply.toString());
            }
         } catch (Exception e) {
            e.printStackTrace();
         } finally {
            try {
               s.close();
            } catch (Exception ignore) {
            }
         }
      }
   }

   private static final class Server implements Runnable {
      private ServerSocket sock = null;

      Server(ServerSocket sock) throws IOException {
         this.sock = sock;
      }

      public void run() {
         System.out.println("starting server");
         try {
            while (true) {
               final Socket client = sock.accept();
               System.out.println("connection accepted");
               Thread t = new Thread(new Runnable() {
                  @Override
                  public void run() {
                     try {
                        ObjectInputStream ois = new ObjectInputStream(client.getInputStream());
                        ObjectOutputStream oos = new ObjectOutputStream(client.getOutputStream());
                        while (!client.isClosed()) {
                           try {
                              Message input = (Message) ois.readObject();
                              oos.writeObject(input);
                              oos.flush();
                           } catch (EOFException eof) {
                              System.err.println("EOF!");
                              client.close();
                           }
                        }
                     } catch (Exception e) {
                        e.printStackTrace();
                     }
                  }
               });
               t.setDaemon(true);
               t.start();
            }
         } catch (Exception e) {
            e.printStackTrace();
         }
      }
   }

   public static void main(String args[]) throws IOException, InterruptedException {
      final int port = 9876;

      Thread ts = new Thread(new Runnable() {
         @Override
         public void run() {
            try {
               new Server(new ServerSocket(port)).run();
            } catch (Exception e) {
               e.printStackTrace();
            }
         }
      });
      ts.setDaemon(true);
      ts.start();

      InetSocketAddress addr = new InetSocketAddress("localhost", port);

      for (int i = 0; i < 2; ++i) {
         Client cl = new Client(addr, i);
         Thread tc = new Thread(cl);
         tc.setDaemon(true);
         tc.start();
      }

      Thread.sleep(10000);
      System.err.println("done");
   }
}
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.