Sending and receiving objects using sockets and threads not working properly

120 views Asked by At

I am currently creating a service allowing to send objects from a client to a server and vice-versa, but experiencing an issue that I unfortunately cannot explain and fix.

First of all, here are the useful classes (I haven't put all methods such as getters and setters in this post).


/**
 * This launcher creates a NetworkInterface, waits for a connection, sends a message to the connected client and waits for an incoming message
 *
 */
public class ServerLauncher {

    public static void main(String[] args) {
        try {
            NetworkSystem n = new NetworkSystem(4096);
            n.startServerManager();

            while (n.getCommunications().isEmpty()) {
                // this line is unexpectedly magic
                System.out.println("Waiting for a new connection...");
            }

            do {
                n.getCommunications().get(0).send(new String("Hello, are you available?")); 
            } while (n.getCommunications().get(0).getReceiveManager().getReadObjects().isEmpty());

            System.out.println(n.getCommunications().get(0).getReceiveManager().getReadObjects().get(0));

        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

/**
 * This launcher creates a NetworkSystem, connects to the server, waits for an incoming message and anwers back
 *
 */
public class ClientLauncher {

    public static void main(String[] args) {
        try {
            NetworkSystem n = new NetworkSystem(8192);
            n.instanciateCommunication(new Socket(InetAddress.getLocalHost(), 4096));

            while (n.getCommunications().get(0).getReceiveManager().getReadObjects().isEmpty()) {
                // this line is unexpectedly magic
                System.out.println("Waiting for an object...");
            }

            System.out.println(n.getCommunications().get(0).getReceiveManager().getReadObjects().get(0));
            n.getCommunications().get(0).getSendManager().send(new String("No, I am not! We will talk later..."));
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

/**
 * This class handles every incoming messages.
 */
public class ReceiveManager implements Runnable {

    private ObjectInputStream inputStream;
    private CommunicationManager communicationManager;
    private List readObjects;
    private boolean receive;

    public ReceiveManager(CommunicationManager communicationManager) throws IOException {
        this.communicationManager = communicationManager;
        this.inputStream = new ObjectInputStream(this.communicationManager.getSocket().getInputStream());
        this.readObjects = new ArrayList();
        this.receive = true;
    }

    @Override
    public void run() {
        Object object = null;

        try {
            while ((object = this.inputStream.readObject()) != null && this.hasToReceive()) {
                this.readObjects.add(object);
            }
        } catch (ClassNotFoundException | IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            this.setContinueToReceive(false);
        }
    }

    private boolean hasToReceive() {
        return this.receive;
    }

    public void setContinueToReceive(boolean value) {
        this.receive = value;
    }
}

/**
 * This class allows the user to send messages
 */
public class SendManager {

    private ObjectOutputStream outputStream;
    private CommunicationManager communicationManager;

    public SendManager(CommunicationManager communicationManager) throws IOException {
        this.communicationManager = communicationManager;
        this.outputStream = new ObjectOutputStream(this.communicationManager.getSocket().getOutputStream());
    }

    public void send(Object object) throws IOException {
        this.outputStream.writeObject(object);
        this.outputStream.flush();
    }
}

So basically, as you may have noticed in the ServerLauncher and the ClientLauncher, there are two "magic" instructions. When those two lines are commented and I run the server then the client, nothing happens. The server and the client are simply running and never stop. However, when I uncomment these two magic lines, every works like a charm: messages are properly sent and received.

Would you guys know the reason of this unexpected behaviour ?

Oh yeah, I forgot, if you guys want me to upload everything to test the project or whatever, just tell me :-)

1

There are 1 answers

0
user207421 On

You're starving the CPU with those spin loops. You should sleep or wait while the queues are empty, or better still just take()from blocking queues.

NB Your loop condition isn't correct:

  1. readObject() doesn't return null at end of stream. It throws EOFException.
  2. You should also test hasToReceive() before calling readObject() rather than afterwards. Otherwise you always do an extra read.