ObjectInputStream(socket.getInputStream()); does not work

24,506

The ObjectInputStream constructor reads data from the given InputStream. In order for this to work, you must flush the ObjectOutputStream immediately after construction (to write the initial header) before you attempt to open the ObjectInputStream. Also, if you want to send more than one object per connection, you must open the ObjectOutputStream once and use it for the lifetime of the socket (e.g. your shareToAll method).

Share:
24,506
Big_Foot1989
Author by

Big_Foot1989

Do just some programming and like to share my knowledge.

Updated on February 13, 2020

Comments

  • Big_Foot1989
    Big_Foot1989 about 4 years


    I'm programming a class to communicate to a server but when it tries to construct the ObjectInputStream with the help of the inputstream the program is freezing. Theres is no Exception and the program is still running but hanging in the line where it tries to construct the ObjectInputstream.

    Heres the code of the method where my problem is located:

    @Override
    public void connect(String ip, int port) throws UnknownHostException, IOException {
        Socket socket = new Socket(ip, port);
        out = new ObjectOutputStream(socket.getOutputStream());
        InputStream is = socket.getInputStream();
        in = new ObjectInputStream(is);
    }
    

    and this is the code for the whole class:

    package Client;
    
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.io.PrintWriter;
    import java.net.Socket;
    import java.net.UnknownHostException;
    
    
    public class MessageStreamerImpl implements MessageStreamer {
        ObjectOutputStream out;
        ObjectInputStream in;
    
        public MessageStreamerImpl(String ip, int port) throws UnknownHostException, IOException{
            connect(ip, port);
        }
    
        public MessageStreamerImpl(){
        }
    
        @Override
        public void send(Object message) throws IOException {
            if(out == null) throw new IOException();
            out.writeObject(message);
            out.flush();
        }
    
        @Override
        public Object receive() throws IOException{
            try {
                return in.readObject();
            } catch (ClassNotFoundException e) {
                throw new IOException();
            }
        }
    
        @Override
        public void connect(String ip, int port) throws UnknownHostException, IOException {
            Socket socket = new Socket(ip, port);
            out = new ObjectOutputStream(socket.getOutputStream());
            InputStream is = socket.getInputStream();
            in = new ObjectInputStream(is);
        }
    
    }
    

    While looking at Google I found this: http://www.coderanch.com/t/232944/threads/java/Socket-getInputStream-block. But I still don't know how to solve the problem, because my ObjectOutputStream constructor is before the one for the ObjectInputStream.

    Here is my server code, maybe it will help ;)

    package Server;
    
    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.net.SocketException;
    import java.util.ArrayList;
    
    public class Server {
        ArrayList<Socket> clients = new ArrayList<Socket>();
    
        public Server(int port){
            try {
                ServerSocket mySocket = new ServerSocket(port);
                waitForClients(mySocket);
            } catch (IOException e) {
                System.out.println("Unable to start.");
                e.printStackTrace();
            }
        }
    
        private void waitForClients(ServerSocket mySocket) {
            while(true){
                try {
                    System.out.println("Ready to receive");
                    Socket client = mySocket.accept();
                    clients.add(client);
                    System.out.println(client.getInetAddress().getHostAddress()+" connected to the Server");
                    Thread t = new Thread(new ClientHandler(client));
                    t.start();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    
        public void shareToAll(Object objectToSchare){
            for(Socket client:clients){
                ObjectOutputStream oos;
                try {
                    oos = new ObjectOutputStream(client.getOutputStream());
                    oos.writeObject(objectToSchare);
                    oos.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    
        private class ClientHandler implements Runnable{
            Socket clientSocket;
    
            public ClientHandler(Socket clientSocket){
                this.clientSocket = clientSocket;
            }
            @Override
            public void run() {
                try {
                    ObjectInputStream ois = new ObjectInputStream(clientSocket.getInputStream());
                    while(true){
                        try {
                            ois.readObject();
    
                        } catch (ClassNotFoundException | IOException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                }catch(SocketException e){
                    System.out.println(clientSocket.getInetAddress().getHostAddress()+" disconnected from the Server");
                    clients.remove(clientSocket);
                }catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }
    

    Thanks for your help I found the fault. It was at the server class which has to look like this:

    package Server;
    
    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.net.SocketException;
    import java.util.ArrayList;
    
    public class Server {
        ArrayList<ObjectOutputStream> clientstreams = new ArrayList<ObjectOutputStream>();
    
        public Server(int port){
            try {
                ServerSocket mySocket = new ServerSocket(port);
                waitForClients(mySocket);
            } catch (IOException e) {
                System.out.println("Unable to start.");
                e.printStackTrace();
            }
        }
    
        private void waitForClients(ServerSocket mySocket) {
            while(true){
                try {
                    System.out.println("Ready to receive");
                    Socket client = mySocket.accept();
                    clientstreams.add(new ObjectOutputStream(client.getOutputStream()));
                    System.out.println(client.getInetAddress().getHostAddress()+" connected to the Server");
                    Thread t = new Thread(new ClientHandler(client));
                    t.start();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    
        public void shareToAll(Object objectToSchare){
            for(ObjectOutputStream stream:clientstreams){
                try {
                    stream.writeObject(objectToSchare);
                    stream.flush();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    
        private class ClientHandler implements Runnable{
            Socket clientSocket;
    
            public ClientHandler(Socket clientSocket){
                this.clientSocket = clientSocket;
            }
            @Override
            public void run() {
                try {
                    ObjectInputStream ois = new ObjectInputStream(clientSocket.getInputStream());
                    while(true){
                        try {
                            ois.readObject();
    
                        } catch (ClassNotFoundException | IOException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                }catch(SocketException e){
                    System.out.println(clientSocket.getInetAddress().getHostAddress()+" disconnected from the Server");
                    clientstreams.remove(clientSocket);
                }catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }   
    }
    

    The most changes you see at the method waitForClients() but I changed, too the concept of my ArrayList and the shareToAll method.

  • Big_Foot1989
    Big_Foot1989 over 12 years
    I don't know if you had the same, but I found the reason. The faul was in the server class at the method waitForClients() I have to generate an Outputstream after Socket client = mySocket.accept(); with client.getOutputstream();. Otherwise the Client is blocked waiting for the OutputStream (his InputStream). Thank you
  • Big_Foot1989
    Big_Foot1989 over 12 years
    I edited the question, because I'm not allowed to answer my own questions yet.
  • Jon Egeland
    Jon Egeland over 12 years
    you still shouldn't be redefining the input and output streams every time. They should be global inside the ClientHandler class.
  • Big_Foot1989
    Big_Foot1989 over 12 years
    That they are. Or they nearly are... but I construct they only once now. The Outputstreams are now represented at my Arraylist and the Inputstream is defied once before the while loop in my ClientHandler ;)