1

I have a Java client-server (using ocsf if anyone here knows it) infrastructure I am using to upload files from client to server. The client is actually an Android app (not sure if that matters that much or not in this case)

I am doing this by reading the file data (bytes), wrapping it in an object that contains some other details (user id, etc..) and sending this object over ObjectOutputStream to the server.

It seems everything works fine until the byte array of the file is over a certain size (not sure what this strange threshold is yet but it seems 645KB is already too much). Then, the server throws a StreamCorruptedException when trying to read the object from the ObjectInputStream and closes the socket.

The code of the object message containing the file bytes:

public class MessageUploadFile extends MessageToServer {

private static final long serialVersionUID = 2356276507283427913L;
private String _destId;
private TransferDetails _td;
private byte[] _fileData;


public MessageUploadFile(String srcId, TransferDetails td, byte[] fileData){
    super(srcId);
    _destId = td.getDestinationId();
    _td = td;
    _fileData = fileData;

}

The client side socket and streams initialization:

 clientSocket= new Socket(host, port);
 output = new ObjectOutputStream(clientSocket.getOutputStream());
 input = new ObjectInputStream(clientSocket.getInputStream());

Sending the message using:

 output.writeObject(msg);  

These are the streams initialization on the server side:

 input = new ObjectInputStream(clientSocket.getInputStream());
 output = new ObjectOutputStream(clientSocket.getOutputStream());

Reading the message using:

 msg = input.readObject();
Nom1fan
  • 846
  • 2
  • 11
  • 27
  • Have a look at this question :http://stackoverflow.com/questions/33067125/error-when-attempting-to-send-kilobyte-message-over-tcp-in-java/33067409#33067409 – Ravindra babu Oct 14 '15 at 13:43
  • @ravindra Thanks for your response. The problem is I am not using and cannot use DataOutputStream. I am sending an object for a reason (so I can send the upload details together with the data). Are you saying this is not possible? If so, how can I correlate this metadata with the file data itself? I thought about using a separate socket and using DataStreams on it but the problem of correlating the metadata remains... – Nom1fan Oct 14 '15 at 14:00
  • Try this way:http://stackoverflow.com/questions/31991831/why-cant-object-size-be-measured-in-a-managed-environment/31995411#31995411 – Ravindra babu Oct 14 '15 at 14:07
  • I always send byte array and re-construct it – Ravindra babu Oct 14 '15 at 14:10
  • So what you are saying is to basically wrap the **OutputStream** in a **ByteArrayOutputStream** and wrap all of this with an **ObjectOutputStream**? If so, should I do this only on the client side or both client and server side? – Nom1fan Oct 14 '15 at 14:13
  • You have to do at both ends. – Ravindra babu Oct 14 '15 at 14:14
  • Doesn't this mean you need to know the type of the object you are sending? In order to re-construct it later? What if I'm sending many kinds of objects as messages? Also, Is this the way to read on the server side: `InputStream inputStream = socket.getInputStream(); // read from the stream ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] content = new byte[ 2048 ]; int bytesRead = -1; while( ( bytesRead = inputStream.read( content ) ) != -1 ) { baos.write( content, 0, bytesRead ); } // while` – Nom1fan Oct 14 '15 at 14:37
  • After reading, if you want to act on that object, construct it and proceed with your operations. Otherwise do not cast to your object.http://www.java2s.com/Code/Java/File-Input-Output/Convertobjecttobytearrayandconvertbytearraytoobject.htm – Ravindra babu Oct 14 '15 at 14:40
  • Ok thanks I will give it a try! One last question though, looking at my code, can you say what exactly causes `StreamCorruptedException` when _fileData is "too large"? Because I would very much like to understand... – Nom1fan Oct 14 '15 at 14:53
  • Since the explanation is long, I will post as answer. I have read some articles like this and changed code. – Ravindra babu Oct 14 '15 at 14:59
  • @ravindra Why? What difference will it make? A. None. – user207421 Oct 15 '15 at 19:13
  • Please post the stack trace in your question, and the exact error message. – user207421 Oct 15 '15 at 19:16

2 Answers2

1
StreamCorruptedException

A Java StreamCorruptedException can be thrown while deserialising data. It essentially occurs in one of two main cases:

you try to open an ObjectInputStream around some data that wasn't actually written using an  ObjectOutputStream

OR

During a  readObject() operation, the stream gets in the "wrong place".

From java docs:

Thrown when control information that was read from an object stream violates internal consistency checks.

But I got this exception with large message and moved to byte array solution.

Have a look at this article:http://www.javamex.com/tutorials/io/StreamCorruptedException.shtml

In summary, convert Object to and from byte array and re-create it.

Ravindra babu
  • 37,698
  • 11
  • 250
  • 211
  • Just found explanation from this one: http://stackoverflow.com/questions/2393179/streamcorruptedexception-invalid-type-code-ac – Ravindra babu Oct 14 '15 at 15:12
  • Thanks for all your help! I really want to adopt your solution. My problem is I feel something still won't be best practice, because I think you should always have the ability to show the user a progress bar of a file upload, and just converting the whole object together with the file data byte array and sending in bulk doesn't allow that. Still feel like I am missing something. – Nom1fan Oct 15 '15 at 11:33
  • I still think you can show the progress bar depending on byte array size. byte[] to Object conversion may not take longer but downloading byte array will take time. – Ravindra babu Oct 15 '15 at 12:17
  • Thanks for all your help! What I did eventually is initially send an object indicating the upload details (fileSize, sender id, etc..) and then on the server side grabbed the underlining inputStream that was in the ObjectInputStream and transferred just the bytes of the files separately. Once finished the client and server continue to communicate via objects. It works fine for now. Thanks! – Nom1fan Oct 15 '15 at 19:07
0

What I did eventually is initially send an object indicating the upload details (fileSize, sender id, etc..) and then on the server side grabbed the underlining inputStream that was in the ObjectInputStream and transferred just the bytes of the files separately. Once finished the client and server continue to communicate via objects. It works fine for now.

Hope this helps someone.

Nom1fan
  • 846
  • 2
  • 11
  • 27