mish
mish

Reputation: 1065

Java NIO Serialization StreamCorruptException Invalid Type Code

I'm trying to transfer an object from a client (normal IO) to a server (NIO). Transmission works fine until the object reaches a certain size, then the server will throw a "StreamCorruptException" saying "invalid type code".

The method called on the server is the following:

  private void read(SelectionKey key) throws IOException, ClassNotFoundException {
    SocketChannel chan = (SocketChannel) key.channel();

    //read message object
    ByteBuffer buf = ByteBuffer.allocate(1024);
    ByteArrayOutputStream bos = new ByteArrayOutputStream(buf.capacity());
    int length = 0;
    int totalRead = 0;
    int read = chan.read(buf);
    System.out.println("read data " + read);
    if (read >= 4) {
      length = IoUtil.readInt(buf.array(), 0);
      bos.write(buf.array());
      buf.rewind();
      totalRead += read;
      LogUtil.log("length of data message is " + length);
    }
    while (totalRead < length) { //read until we get no more data
      read = chan.read(buf);
      if (read == -1) break;
      if (read == 0) continue;
      totalRead += read;
      System.out.println("I've read " + read + " bytes. Total amount of bytes " + totalRead);
      bos.write(buf.array());
      buf.rewind();
    }

    ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray(), 4, length);
    ObjectInputStream inFromClient = new ObjectInputStream(bis);

    Message msg = (Message) inFromClient.readObject();

    SocketAddress sa = chan.socket().getRemoteSocketAddress();
    LogUtil.log(msg.getIdentifier() + "-Message von " + sa);


    commData.handleMessage(sa, msg);

  }

I prepend the size of the object to make NIO play nicely. What am I missing here?

Upvotes: 1

Views: 184

Answers (1)

Peter Lawrey
Peter Lawrey

Reputation: 533500

You have to consider that a message can be fragmented (which is what I suspect is happening here) or coalessed. This means you cannot assume that the start of a message and end of a message will be at the start or end of a read. (It typically is for small messages with a significant break between them, but this fails randomly)

The safe approach is to send a length at the start and read until you have that length. If you have more, keep the extra for the next read.

Upvotes: 2

Related Questions