3

The Application

I'm writing a client/server application in Java, that communicates by sending objects over sockets using the ObjectStream classes. Each node in the application looks approximately like this:

class Node {
  SocketServer server;
  Socket[] clients;
}

Here the server variable is the socket on which this node listens, and the client variables are the sockets on which other nodes listen, and to which this node sends objects.

The code that I use to write objects to one of the client sockets looks like this:

void sendMessage(Message<B, F> msg) throws IOException {
    ObjectOutputStream writer = getWriter();
    writer.writeObject(msg);
    writer.flush();
}

private ObjectOutputStream writer;

ObjectOutputStream getWriter() throws IOException {
    if (writer == null)
        writer = new ObjectOutputStream(
            new BufferedOutputStream(client.getOutputStream()));
    return writer;
}

And the code that I use to handle connections and read objects from the node's server socket looks like this:

// the handler will listen for connections
final Thread handler = new Thread(new Runnable() {

    public void run() {
        try {
            // create a new thread to handle the client
            final Socket client = server.accept();
            final Thread thread = new Thread(new Runnable() {

                public void run() {
                    final ObjectInputStream reader;
                    try {
                        reader = new ObjectInputStream(client.getInputStream());
                        while (true) {
                            try {
                                val msg = reader.readObject();
                                messages.add((Message<B, F>) msg);
                            }
                            catch (EOFException e) {
                                // i noted it seemed to throw eofexceptions
                            }
                            catch (IOException e) {
                                // do something
                            }
                        }
                    }
                    catch (IOException e) {
                        // do something
                    }
                }
            });
          thread.start();
        } catch (IOException e) {
            // do something
        }
    }
});
handler.start();

The Problem

I think I'm doing something wrong with the sockets here. Everything works fine when every server is only connected to a single client. However, when multiple clients are talking to the same server things go bad, and I get StreamCorruptedException's from the ObjectInputStream and other strange behaviour (putting in an instance of an UpdateRequest message, and getting out an instance of Integer(0) and some exceptions, for example.)

My intuition tells me that somehow the two object/byte streams are getting intermingled, and this produces the strange results when attempting to deserialize the objects. My question is: why is this happening aka what am I doing wrong, and how could I fix it?

wen
  • 3,782
  • 9
  • 34
  • 54
  • 1
    When do you close your reader? – Amir Raminfar Jun 24 '11 at 20:07
  • Looks like a possible synchronisation problem to me. Is there more than one thread that may be writing to the ObjectOutputStream? Also, try not to call it `writer`. Writer implies text rather than binary data. – Dunes Jun 24 '11 at 20:14
  • @Amir Oooh, more importantly, how do you close the writer? – Dunes Jun 24 '11 at 20:17
  • It's been a while since I've done any Java networking like this, but I remember when I was first learning it the Java Socket tutorial was a huge help to me. Maybe it's a good reference for you as well. http://www.oracle.com/technetwork/java/socket-140484.html#multi – Nick DeFazio Jun 24 '11 at 20:22
  • Uhm... I dont close the outputstreams as this would give me an exception saying the socket had closed. What kind of errors could this cause, and why? – wen Jun 24 '11 at 21:43
  • Actually, I close them in Object#finalize. Might be horrible practice or not even work... If so please tell me. Before I used lombok's @Cleanup. – wen Jun 24 '11 at 21:45
  • I do think the problem had something to do with concurrency and writing/reading sockets. Moving some of the mechanics to run in separate threads helped (though I may have overdone it). – wen Jun 28 '11 at 22:54

2 Answers2

1

You have an array of Sockets but you don't appear to have an array of writers and readers. So you're probably using the same writer and reader for all connections.

Really you should have a per-connection Connection object, that implements Runnable, and that has the Socket, the writer, and the reader as instance members.

Also when you catch EOFException you must break out of the loop and close the writer.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • You make a good point against my explanation - I have one implementation of the class that has `sendMessage` and `getWriter` PER client socket, so this is not the issue. – wen Jun 25 '11 at 01:53
  • Furthermore, could you explain more about the EOFException and the breaking/closing? – wen Jun 25 '11 at 01:53
  • @Pepijn it seems clear to me. When you get an EOFException there is nothing more to read, so you must stop reading, close the file, exit the read loop, ... – user207421 Jun 27 '11 at 00:10
0

The problem was occurring due to messages being sent simultaneously, and this resulted in the bytes being mixed. The solution was to make sure that messages would only be received one at a time.

wen
  • 3,782
  • 9
  • 34
  • 54