0

I have multiple clients and one server. Server handles each client in one thread. Clients must send a custon object to the master. I checked this and this, which talk about the error java.io.StreamCorruptedException: invalid type code: AC which is exactly I'm having.

But I didn't understood the proposed solution. He inherits the ObjectOutputStream and simple does not write the header in the second and following times the object must be sent. This is not working for me.

Is there another solution to send custom objects throught TCP sockets? My clients gather their data every 10 seconds and re-created the object which is sent.

I'm sorry if i'm being repetitive, I'm reading a lot of similar question but finding no answers to my scenario.

Thanks in advance

EDIT

Send method (in the client)

    public void TCPEchoClientSend(MonitoredData _mData) throws IOException {
        if (_mData == null)
            throw new IllegalArgumentException("Parameter: <Monitored Data> empty.");           
        ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());

        // Send the encoded object to the server
        oos.writeObject(_mData);

        oos.close();

        System.out.println("Client sent the monitored data package.");

    }

Receive

public static void handleEchoClient(Socket client, Logger logger) {
        try {
            MonitoredData mdata;
            // Get the input and output I/O streams from socket
            ObjectInputStream ois = new ObjectInputStream(client
                    .getInputStream());
            ObjectOutputStream oos = new ObjectOutputStream(client
                    .getOutputStream());

            // Receive until client closes connection, indicated by -1;
            while ((mdata = (MonitoredData) ois.readObject()) != null) {

                System.out.println("Got received data. Ready to save.");

                hdb.saveOrUpdate(mdata);

                System.out.println("Monitored Data arrived at home.");

            }

            // logger.info("Client " + _clntSock.getRemoteSocketAddress()+
            // ", echoed " + totalBytesEchoed + " bytes.");

        } catch (IOException ex) {
            logger.log(Level.WARNING, "Exception in echo protocol", ex);
        } catch (ClassNotFoundException e) {
            logger.log(Level.WARNING, "Exception in echo protocol", e);
        } finally {
            try {
                client.close();
            } catch (IOException e) {
            }
        }
    }
Community
  • 1
  • 1
Pedro Dusso
  • 2,100
  • 9
  • 34
  • 64

2 Answers2

2

Use the same ObjectOutputStream and ObjectInputStream for the life of the socket, at both ends, and look up the ObjectOutputStream reset() and writeUnshared() methods.

See this answer for a discussion.

Community
  • 1
  • 1
user207421
  • 305,947
  • 44
  • 307
  • 483
  • So I should instantiate them outside my send/receive methods? Like in the constructor, for example? – Pedro Dusso Jul 18 '12 at 23:31
  • Well, apparently it worked :) thanks in advance, I still have to keep studying these streams – Pedro Dusso Jul 18 '12 at 23:43
  • @PedroDusso Well done. In fact you should always use the same streams/readers/writers for the life of the socket regardless of what type they are, for buffering reasons and also just for economy of effort. – user207421 Jul 18 '12 at 23:53
-1

ObjectInputStream and ObjectOutputStream are stateful. So you need to match their lifecycles. Are you instantiating a new output stream in each client every time it is sending a web of objects (i.e. every 10 seconds)? Is so, you're best off instantiating a corresponding input stream in the server. Note that this is the safest and cleanest option, but it sends more data over the wire.

On the other hand, if you are keeping the streams around, then you need to worry about several things. First, are you sending only immutable objects? Otherwise, you may not communicate the desired content (serialization writes each object only once and then writes references to the object that was serialized earlier).

Dilum Ranatunga
  • 13,254
  • 3
  • 41
  • 52
  • Being stateful isn't the only reason you need to match the lifecycles: there is a stream header, which is the source of the AC; and using new streams per write & read isn't the 'safest and cleanest option'. – user207421 Jul 18 '12 at 22:33
  • @EJP, I didn't mean per-write. More like per 'transaction' in a loose sense. Basically, if you end up re-writing an object that has changed since the first write, you are asking for trouble. – Dilum Ranatunga Jul 19 '12 at 02:20
  • 1
    Not at all, you just call reset() when you want to resend it, or before each 'transaction'. – user207421 Jul 22 '12 at 03:52