0

I am trying to establish a connection to a socket server that reads and writes using Object Streams. I am able to send objects to the server, but when I try use the ObjectInputStream to listen for a response, I get an error.

note debug.debug() is a wrapper around sout

My client:

public class Client {

    ObjectInputStream in;
    ObjectOutputStream out;

    Debug debug = new Debug();

    /**
     * Connect to a local socket server and start IO streams
     * @param port Port to connect to
     */
    public void connect(Integer port) {

        try{
            Socket socket = new Socket("localhost", port);
            debug.debug("CONNECTED", "GREEN");

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

            while (true) {
                try {
                    handleResponse(in.readObject());
                } catch (IOException e) {
                    debug.debug("CONNECTION_LOST", "ERROR");
                    break;
                }
            }
            connect(8080);
        } catch (Exception e) {
            debug.debug("Could not connect to host", "ERROR");
            try {
                Thread.sleep(3000);
                connect(8080);
            } catch (InterruptedException ex) {
                debug.debug("Sleep failed", "ERROR");
            }
        }
    }

    public void out(Model model) {

        try {
            out.reset();
            out.writeObject(model);
            debug.debug("Sent serialized object to server. [" + model.model + "]");
        } catch (IOException e) {
            debug.debug("Could not write object", "ERROR");
        }
    }

    private void handleResponse(Object model) {

        if (model instanceof User)
            if (((User)model).authorized)
//                ((User)model).dispatch();
                debug.debug("accepted");
    }

    public void main(String[] args) throws InterruptedException {

        connect(8080);
    }
}

Login class:

public final class Login extends JComponent implements Dispatcher {

    Button login;
    TextField email;
    PasswordField password;

    User User = new User();

    Debug debug = new Debug();

    public Login() {

        setLayout(new GridBagLayout());

        login = new Button("LOGIN", null);
        email = new TextField();
        password = new PasswordField();

        login.addActionListener(e -> {
            if (!email.getText().equals(""))
                if (!password.getText().equals("")) {
                    User.email = email.getText();
                    User.password = password.getText();
                    Admin.Socket.out(User);
                }
        });

        build();
    }

    public void userAuthorized() {

        debug.debug("authorized");
    }

    public void build() {

        GridBagConstraints constraint = new GridBagConstraints();

        constraint.anchor = GridBagConstraints.PAGE_START;
        constraint.gridx = 0;
        constraint.gridy = 0;
        constraint.gridheight = 1;
        constraint.gridwidth = 2;

        constraint.ipadx = 250;
        add(email, constraint);
        constraint.insets = new Insets(10, 0, 0, 0);
        constraint.gridy = 1;
        add(password, constraint);
        constraint.gridy = 2;
        constraint.ipadx = 100;
        constraint.ipady = 15;
        add(login, constraint);
    }
}

This gives me a java.lang.NullPointerException when I call the out method. However if I instead use a BufferedReader to listen, then everything works as expected.

    public void connect(Integer port) {

        try{
            Socket socket = new Socket("localhost", port);
            debug.debug("CONNECTED", "GREEN");

            // BufferedReader instead of ObjectInputStream
            in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            out = new ObjectOutputStream(socket.getOutputStream());

            while (true) {
                try {
//                    handleResponse(in.readObject());
                    debug.debug(in.readLine());
                } catch (IOException e) {
                    debug.debug("CONNECTION_LOST", "ERROR");
                    break;
                }
            }
            connect(8080);
        } catch (Exception e) {
            debug.debug("Could not connect to host", "ERROR");
            try {
                Thread.sleep(3000);
                connect(8080);
            } catch (InterruptedException ex) {
                debug.debug("Sleep failed", "ERROR");
            }
        }
    }

When I call out, the server receives the sent object. However now I cannot listen for objects returned by the server. What am I doing wrong?

EDIT stack trace:

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
    at socket.Client.out(Client.java:59)
    at applications.admin.components.Login.lambda$new$0(Login.java:48)
    at applications.admin.components.Login$$Lambda$6/500977346.actionPerformed(Unknown Source)
    at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2022)
    at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2346)
    at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:402)
    at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:259)
    at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:252)
    at java.awt.Component.processMouseEvent(Component.java:6527)
    at javax.swing.JComponent.processMouseEvent(JComponent.java:3321)
    at java.awt.Component.processEvent(Component.java:6292)
    at java.awt.Container.processEvent(Container.java:2234)
    at java.awt.Component.dispatchEventImpl(Component.java:4883)
    at java.awt.Container.dispatchEventImpl(Container.java:2292)
    at java.awt.Component.dispatchEvent(Component.java:4705)
    at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4898)
    at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4533)
    at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4462)
    at java.awt.Container.dispatchEventImpl(Container.java:2278)
    at java.awt.Window.dispatchEventImpl(Window.java:2739)
    at java.awt.Component.dispatchEvent(Component.java:4705)
    at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:746)
    at java.awt.EventQueue.access$400(EventQueue.java:97)
    at java.awt.EventQueue$3.run(EventQueue.java:697)
    at java.awt.EventQueue$3.run(EventQueue.java:691)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:75)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:86)
    at java.awt.EventQueue$4.run(EventQueue.java:719)
    at java.awt.EventQueue$4.run(EventQueue.java:717)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:75)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:716)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)

EDIT Server:

public class Server {

    static Debug debug = new Debug();

    /**
     * Start a socket server
     */
    public void listen(Integer port, TextArea logs) {

        logs = logs != null ? logs : new TextArea();

        try {
            ServerSocket server = new ServerSocket(port);
            debug.debug("Server is running", "GREEN", logs);

            while (true) {
                Handler handler;
                try {
                    handler = new Handler(server.accept(), logs);
                    Thread client = new Thread(handler);
                    client.start();
                } catch (IOException e) {
                    debug.debug("CLIENT_ACCEPT Failed", "ERROR", logs);
                    System.exit(-1);
                }
            }

        } catch (IOException e) {
            debug.debug("SERVER_START Failed", "ERROR", logs);
        }
    }

    public void main(String[] args) throws InterruptedException {

        listen(8080, null);
    }
}

Handler:

public class Handler implements Runnable {

    Socket client;
    Debug debug = new Debug();

    ObjectInputStream in;
    ObjectOutputStream out;

    TextArea logs;

    User user = new User();

    /**
     * Client instance running on new thread
     *
     * @param client Client Socket
     */
    Handler(Socket client, TextArea logs) {

        this.client = client;
        this.logs = logs;
        debug.debug("CLIENT_CONNECTED", "GREEN", logs);
    }

    /**
     * Listen to the client Stream and respond
     */
    @Override
    public void run() {

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

            while (true) {
                try {
                    try {
                        handleResponse((User) in.readObject());
                    } catch (ClassNotFoundException e) {
                        debug.debug("Unable to read object", "ERROR", logs);
                    }
                } catch (IOException e) {
                    debug.debug("CLIENT_DISCONNECTED", "ERROR", logs);
                    break;
                }
            }
        } catch (IOException e) {
            debug.debug("CONNECTION_FAILED", "ERROR", logs);
        }
    }

    private void handleResponse(User user) {

        debug.debug("Received serialized object from client. [" + user.model + "]", logs);

        if (user.auth()) {
            try {
                out.reset();
                out.writeObject(user);
                debug.debug("server: AUTHORIZED", "GREEN", logs);
            } catch (IOException e) {
                debug.debug("Couldn't write object", "ERROR", logs);
            }
        } else {
            debug.debug("server: UNAUTHORIZED", "ERROR", logs);
        }
    }
}
12
  • Please provide the exact exception message and the stack trace. Commented Jul 22, 2015 at 21:18
  • I know this. That is where I call the out method. Commented Jul 22, 2015 at 21:28
  • What does handleResponse(...) do ? It is your own method or the one in Apache utils ? Commented Jul 22, 2015 at 21:33
  • This is my own method. It simply logs out the value of a variable within the object returned from the server. I can replace it with System.out.println(((User)in.readObject()).email); Commented Jul 22, 2015 at 21:35
  • Is that a multi-threaded application and are Client.out(...) and Client.connect(...) called in parallel? Commented Jul 22, 2015 at 21:53

1 Answer 1

1

It's not clear how the Client and Login classes are connected, so I'll just guess.

ObjectInputStream constructor, as said in the javadoc, "will block until the corresponding ObjectOutputStream has written and flushed the header". So your Client.connect() thread freezes at the in = new ObjectInputStream(...) line and doesn't set values for in and out. (Actually, the server thread also freezes for the same reason, so you have a deadlock.) Meanwhile, Login thread tries to write something to out, but out is still null, so it gets a NullPointerException.

Why doesn't this happen with BufferedReader? It doesn't block in the constructor, so the thread just continues execution, sets non-null value for out and everyone is happy.

Fix: create ObjectOutputStream first and flush it, so that ObjectInputStream on the other end doesn't have to wait. In other words, change

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

to

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

in both client and server.


Another problem, which you may face after you've fixed the first one, is that Client.out field is not volatile and there is no obvious synchronization, so Login thread may see null there even after out is set to a non-null value in Client.connect() thread. So I suggest you make Client.out field volatile (and maybe Client.in too).

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.