problem in sending serializable objects using ObjectInputStream - java

snippet from The Server code :
public void run() {
try {
// Create data input and output streams
ObjectInputStream inputFromClient = new ObjectInputStream(
socket.getInputStream());
ObjectOutputStream outputToClient = new ObjectOutputStream(
socket.getOutputStream());
while (true) {
cop = inputFromClient.readObject();
String[][] m1=new String[][] {{"1", "1","1"}};
Object xx=new getSerialModel(m1);
outputToClient.reset();
outputToClient.writeObject(xx);
outputToClient.flush();
}
}
snippet from the Client :
//////////////
/// sockt jop
try {
// Create a socket to connect to the server
socket = new Socket("127.0.0."+Math.round(50+Math.random()*50), 8000);
// Create an output stream to send data to the server
toServer = new ObjectOutputStream(socket.getOutputStream());
toServer.flush();
}
catch (IOException ex) {
msgArea.append('\n' + ex.toString() + '\n');
}
///////////////////
//***
///////////////////
buttonSave.addActionListener(new ActionListener()
{ public void actionPerformed(ActionEvent ev)
{
System.out.println("Saving data is not implemented yet.");
String[][] m1={{"0","0","0"}};
for ( int i = 0 ; i < tableModel.getRowCount() ; i++ ){
{ for ( int j = 0 ; j < tableModel.getColumnCount() ; j++ )
m1[i][j]=(String)tableModel.getValueAt(i, j) ;
}
}
getSerialModel obt =new getSerialModel(m1);
try{
toServer.reset();
toServer.writeObject(obt);
toServer.flush();
}
catch (Exception ex) {
msgArea.append("cant reach the server its may be off" + '\n');
}
}
});
// button send msg
buttonsendtest.addActionListener(new ActionListener()
{ public void actionPerformed(ActionEvent ev)
{
try{
fromServer = new ObjectInputStream(socket.getInputStream());
Object mdata = fromServer.readObject();
tableModel.setDataVector((((getSerialModel)mdata).getmodel()), columnNames);
table.updateUI();
}
catch (Exception ex) {
System.out.print(ex.getStackTrace());
msgArea.append("cant reach the server its may be off "+ ex.toString() + '\n');
}
}
});
When I try to read serializable object from the server multible times , I get this exception , for first time the reciever read it successfully .
java.io.StreamCorruptedException: invalid stream header: 00007571
how can I fix it ?

If you are creating multiple ObjectInputStream instances in series for the same socket input stream, this seems like a bad idea. If the server is writing multiple objects to the same output stream, then there is serialization-related information that only gets sent once per unique object, and only the first ObjectInputStream instance on the client would be able to reliably read this. Using only one ObjectInputStream instance per socket input stream and one ObjectOutputStream instance per socket output stream is probably the safest implementation.
Also, if you are writing multiple objects to the same ObjectOutputStream instance on the server side (i.e., multiple writeObject() calls), this can result in stream header problems due to potentially multiple references to the same objects (typically nested references) when they are read by the client's input stream
This problem occurs when the object output stream wraps a socket output stream since during normal serialization, the second and later references to an object do not describe the object but rather only use a reference. The client's ObjectInputStream does not reconstruct the objects properly for some reason due to a difference in the header information it is expecting (it doesn't retain it from previous readObject() calls); this only seems to happen with socket streams, not file I/O, etc. This problem does not occur with the first readObject() call but rather the second and subsequent ones.
If you want to continue to use the same socket stream to write multiple objects, you will need something like the following in the server code:
objectOut.reset()
objectOut.writeObject(foo);
The reset() call re-initializes the stream, ignoring the state of any objects previously sent along the stream. This ensures that each object is sent in its entirety without the handle-type references that are typically used to compress ObjectOutputStream data and avoid duplication. It's less efficient, but there should be no data corruption when read by the client.

From the documentation for ObjectInputStream.readObject(), I quote:
Read an object from the ObjectInputStream. The class of the
object, the signature of the class,
and the values of the non-transient
and non-static fields of the class and
all of its supertypes are read.
Default deserializing for a class can
be overriden using the writeObject and
readObject methods. Objects referenced
by this object are read transitively
so that a complete equivalent graph of
objects is reconstructed by
readObject.
The root object is completely restored when all of its fields and
the objects it references are
completely restored. At this point the
object validation callbacks are
executed in order based on their
registered priorities. The callbacks
are registered by objects (in the
readObject special methods) as they
are individually restored.
Exceptions are thrown for problems with the InputStream and for classes
that should not be deserialized. All
exceptions are fatal to the
InputStream and leave it in an
indeterminate state; it is up to the
caller to ignore or recover the stream
state.
Specified by:
readObject in interface ObjectInput
Returns:
the object read from the stream
Throws:
ClassNotFoundException - Class of a serialized object cannot be found.
InvalidClassException - Something is wrong with a class used by serialization.
StreamCorruptedException - Control information in the stream is inconsistent.
OptionalDataException - Primitive data was found in the stream instead of objects.
IOException - Any of the usual Input/Output related exceptions.
I'd guess that you're trying to read an object before one has been written to the object stream, or one where the output stream hasn't been flushed.

You are trying to read in an object of type 'Object'. Is that how it was serialized? You need to make sure that you are reading the object into the same class that it was written from, remember those pesky serialVersionUID warnings that come up? This is key to object serialization and reconstruction, hence the need for matching classes. Also the reason that you need to update your UID when your class structure changes.

Perhaps you're trying to read multiple times the same object from the stream, while the server wrote the object only once.
Or you're trying to use an ObjectInputStream before a corresponding ObjectOutputStream is created, and that invalidates the communication between the two. An ObjectOutputStream writes a serialization stream header upon its creation, and if it's not created before the corresponding ObjectOutputStream, that header is lost.

Related

Server gets StreamCorruptedException when more than one object received [duplicate]

My problem is when it tries to read the object the second time, it throws the exception:
java.io.StreamCorruptedException: invalid type code: AC
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1356)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:351)
at Client.run(BaseStaInstance.java:313)
java.io.StreamCorruptedException: invalid type code: AC
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1356)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:351)
at Client.run(BaseStaInstance.java:313)
The first time I send the exact same object message; however, when I try doing the same thing the second time, it throws the error above. Do I need to re-intialize the readObject() method? I even printed out the message object that is being received by the line below and its exact the same as the first instance where it works ok.
Object buf = myInput.readObject();
I'm assuming there's some problem with appending, but I really have no use for appending. I just want to read a fresh line everytime.
I'd really appreciate some help in fixing this bug. Thank you.
==================================
Before that one line, I'm just creating the input and output objects for the socket in the run() method. The object declaration is outside the run() method in the class:-
#Override
public void run() {
try {
sleep((int) 1 * 8000);
} catch (Exception e) {
e.printStackTrace();
}
try {
//Creating input and output streams to transfer messages to the server
myOutput = new ObjectOutputStream(skt.getOutputStream());
myInput = new ObjectInputStream(skt.getInputStream());
while (true) {
buf = myInput.readObject();
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
} catch (Exception e) {
e.printStackTrace();
}
}
}
You're right; I don't close the object. I'm not sure how to do that.
The underlying problem is that you are using a new ObjectOutputStream to write to a stream that you have already used a prior ObjectOutputStream to write to. These streams have headers which are written and read by the respective constructors, so if you create another ObjectOutputStream you will write a new header, which starts with - guess what? - 0xAC, and the existing ObjectInputStream isn't expecting another header at this point so it barfs.
In the Java Forums thread cited by #trashgod, I should have left out the part about 'anew for each object at both ends': that's just wasteful. Use a single OOS and OIS for the life of the socket, and don't use any other streams on the socket.
If you want to forget what you've written, use ObjectOutputStream.reset().
And don't use any other streams or Readers or Writers on the same socket. The object stream APIs can handle all Java primitive datatypes and all Serializable classes.

How to use readObject() twice in socket of Java?

I used the ObjectStream in Socket to transport the class.
The client transports two different data in same class, but the server gets the second data that is same as the first data. It is strange!
Here is my code of client:
public Client()
{
MessageClass messageobject=new MessageClass("login");
messageobject.SetLoginUserInfo("18580409","12345","magicgiant");
try
{
client=new Socket("localhost",1234);
System.out.println("Connected!");
ObjectOutputStream out=new ObjectOutputStream(client.getOutputStream());
out.writeObject(messageobject);
out.flush();
System.out.println(1);
messageobject.inquire=true;
messageobject.SetLoginUserInfo("122131","21312","dfsd");
out.writeObject(messageobject);
out.flush();
System.out.println(2);
}
catch(Exception e)
{
System.out.println(e);
}
}
Here is my server:
public void run()
{
try
{
is=new ObjectInputStream(client.getInputStream());
}
catch (Exception ex)
{
System.out.println(ex);
}
while(true){
try
{
MessageClass messageobject = (MessageClass)is.readObject();
System.out.println(messageobject.GetLoginId()+messageobject.GetLoginPassword());
idSocketItem = new IdSocket(messageobject.GetLoginId(),client,messageobject);
s.idSocketList.addElement(idSocketItem);
}
catch (Exception ex)
{
System.out.println(ex);
}
}
}
The System.out in server should be
1858040912345
12213121312
But the real result is
1858040912345
1858040912345
I have tried to cancel the flush(), but it does not work.
Where is the problem?
The problem is that you're writing the same reference twice:
out.writeObject(messageobject);
out.flush();
System.out.println(1);
messageobject.inquire=true;
messageobject.SetLoginUserInfo("122131","21312","dfsd");
out.writeObject(messageobject);
ObjectOutputStream caches the fact that you've written that reference, and just emits a token to refer to the previous value. Three options to consider:
(Preferred, IMO): Create a new object instead of modifying the existing one
Call writeUnshared() instead of writeObject():
This method is identical to writeObject, except that it always writes the given object as a new, unique object in the stream (as opposed to a back-reference pointing to a previously serialized instance).
Call reset() on the stream after writing the first object:
Reset will disregard the state of any objects already written to the stream. The state is reset to be the same as a new ObjectOutputStream. The current point in the stream is marked as reset so the corresponding ObjectInputStream will be reset at the same point. Objects previously written to the stream will not be refered to as already being in the stream. They will be written to the stream again.
I prefer the first version as logically you've got two different messages - so they should be two different objects.
Additionally, I'd strongly encourage you to start following Java naming conventions, and make all your fields private to encourage encapsulation.

How to reset ObjectInputStream objects graph cache to avoid memory bloat

When loading huge files with ObjectInputStream, all read objects are buffered by stream for object graph resolving.
This cause huge memory overhead which isn't needed in my case (all objects read are interdependent).
Is there an equivalent to the reset() method of ObjectOutputStream which reset this buffer?
Code example:
try (FileInputStream fileInputStream = new FileInputStream(filename);
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
ObjectInputStream objectInputStream = new ObjectInputStream(bufferedInputStream)) {
while (object = objectInputStream.readObject()) {
System.Out.println(object.toString());
}
}
There is actually a reset method on the class but it does a complete different thing.
See Java APIs which cause memory bloat
It's up to the sender to decide when to break the integrity of sent object graphs, by calling ObjectOutputStream.reset(). Not the receiver.
NB your code doesn't compile, and wouldn't be valid if it did:
while (object = objectInputStream.readObject()) {
}
This should be
try {
while (true) {
object = objectInputStream.readObject();
// ...
}
}
catch (EOFException exc) {
// end of stream
}
There is a misconception abroad that readObject() returns null at end of stream. It doesn't. It throws EOFException. It can return null any time you wrote a null.
Hmm it seems you need to use some sort of lazy loading techniques where you only load necessairy components of the object graph, not everything.

Android - Pass object via bluetooth

The Bluetooth chat example for Android is very useful to learn how to pass strings between phones - is it possible to use the same code to pass objects between phones? I have the same classes defined in both phones, I just want to pass the instance of one class from one phone to another. Is there any sample code available? I tried using serialization and replacing outputstream and inputstream in the chat example with objectoutputstream and objectinputstream but it didn't seem to work
The best way I found to handle this was the following:
I set up my objects as implementing Serializable that I wanted to send.
I set up the following code to manage the messages:
public byte[] serialize() throws IOException {
ByteArrayOutputStream b = new ByteArrayOutputStream();
ObjectOutputStream o = new ObjectOutputStream(b);
o.writeObject(this);
return b.toByteArray();
}
//AbstractMessage was actually the message type I used, but feel free to choose your own type
public static AbstractMessage deserialize(byte[] bytes) throws IOException, ClassNotFoundException {
ByteArrayInputStream b = new ByteArrayInputStream(bytes);
ObjectInputStream o = new ObjectInputStream(b);
return (AbstractMessage) o.readObject();
I changed the write statements to accept a Serializable, and then make the final write:
/**
* Write to the connected OutStream.
* #param buffer The bytes to write
*/
public void write(AbstractMessage buffer) {
try {
Log.v(TAG,"Writing \""+(buffer.serialize())+"\"");
mmOutStream.write(buffer.serialize());
// Share the sent message back to the UI Activity
mHandler.obtainMessage(AbstractMessageManager.MESSAGE_WRITE, -1, -1, buffer)
.sendToTarget();
} catch (IOException e) {
Log.e(TAG, "Exception during write", e);
}
}
The Bluetooth Chat example is a demonstration of using the Serial Port Profile (SPP) which is based upon RFCOMM. You can serially send across any data you like once the connection is established; you simply need to be able to represent your objects into a serial stream of bytes, i.e. serialize them.
Therefore the use of serialization would certainly be a way of getting your objects sent over the link. The Bluetooth API's send and receive functions deal with arrays of bytes, but you could easily adapt the Bluetooth Chat example to use streams, e.g. the send function would read bytes out of a stream and put them into an array buffer, then you send that buffer, etc. Then the application code would simply talk via input and output stream pipes - that's one way I've done it in the past.
So there's nothing wrong with your actual idea. The bigger problem is that the way you've implemented it is not right, and more problematic still is that the way you've asked your question is quite poor, too. You need to be more descriptive about exactly what didn't work, explain what debugging you've already tried, and post code samples and Logcat outputs so we can help you properly.
Finally, I did find what I think is a bug in the Bluetooth Chat code example: The data receive function passes a reference of the receive byte array to the ArrayList that's used to show each line of text received. This is alright when small amounts of slow text are being transmitted across, but when you try to send large amounts of data, you start to see the data being corrupted, presumably because the ArrayList adapter is still reading bytes out of that same array when the array is being filled with even newer data.
The answer is yes. A String is an Object. Remember? But how exactly to do it, I am still searching for a solution and that's what brought me here...
Trev16v,
First of all, thanks for your initial feedback.
In order to serialise my object, I used the classes serializeObject and deserializeObject from
http://www.jondev.net/articles/Android_Serialization_Example_(Java)
They seem to work well: if I serialise an object (created out of a class that implements Serializable) from a phone/activity and deserialize it from the same phone i manage to get an object out of the generated byte[].
I then tried to use the same code in the class BluetoothChatServices in the bluetooth chat example in oder to send the serialised object to the other phone (in that example there is
public ConnectedThread(BluetoothSocket socket) {
Log.d(TAG, "create ConnectedThread");
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the BluetoothSocket input and output streams
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) {
Log.e(TAG, "temp sockets not created", e);
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
and the bytes are passed using
public void write(byte[] buffer) {
try {
mmOutStream.write(buffer);
// Share the sent message back to the UI Activity
mHandler.obtainMessage(BluetoothChat.MESSAGE_WRITE, -1, -1, buffer)
.sendToTarget();
} catch (IOException e) {
Log.e(TAG, "Exception during write", e);
}
}
and read using
public void run() {
Log.i(TAG, "BEGIN mConnectedThread");
byte[] buffer = new byte[10240];
int bytes;
// Keep listening to the InputStream while connected
while (true) {
try {
// Read from the InputStream
bytes = mmInStream.read(buffer);
// Send the obtained bytes to the UI Activity
mHandler.obtainMessage(BluetoothManageActivity.MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
} catch (IOException e) {
Log.e(TAG, "disconnected", e);
connectionLost();
break;
}
}
}
The problem with using BluetoothChatServices as it is is that the array of bytes received on the other phone is different from the one sent when it comes to serialised objects. For example, to give an idea element [0] of the seriealized object is =-84 when i send it, the one i receive from the other phone has element [0] to [4] =0, then [5]=4 and all the other elements are also not aligned. I tried in the methods write and run above to change Inputstream and Outputstream with ObjectInputStream and ObjectOutputstream but without success (if this was supposed to be the way to implement it, I can post the code I tried to use)
Again, thanks a lot for your help, I am new to all these concepts so if I am talking nonsense I will be also happy to be addressed to a tutorial
thanks
Facing same problem ... When i am sending a series of objects from one Android device, data sends properly ... But in receiving end all objects does not construct from received byte[].
Error occurs randomly for any received object but the same code works properly in Java ... I think the some bytes misses when transferring data from one device to another ...
Serializable object to byte[] and byte[] to object conversion can be done with the following code
public static byte[] toByteArray(Object obj)
{
byte[] bytes = null;
ObjectOutputStream oos = null;
try
{
oos = new ObjectOutputStream(new ByteArrayOutputStream());
oos.writeObject(obj);
oos.flush();
return bos.toByteArray();
}
catch(Exception e)
{
Log.e("Bluetooth", "Cast exception at sending end ...");
}
return bytes;
}
public static Object toObject(byte[] bytes)
{
Object obj = null;
ObjectInputStream ois = null;
try
{
ois = new ObjectInputStream(new ByteArrayInputStream(bytes));
return ois.readObject();
}
catch(Exception ex)
{
Log.e("Bluetooth", "Cast exception at receiving end ...");
}
return obj;
}
I actually found the problem - when the bytes are loaded using
try {
// Read from the InputStream
bytes = mmInStream.read(buffer);
they are actually loaded in 2 steps.. While debugging and stepping into the code I found that if first loads 990 bytes and then the remaining bytes.. so when i am back to the UI handler i see only the bytes loaded in the second step..
i wonder if there is a way to force to load all bytes at once

Question with sending object over java sockets

So I have been working on a 2 player Tic-Tac-Toe game in java that utilizes sockets. All of the socket stuff is working, and I am sending data back and forth successfully between 2 clients and a server.
I have the following classes: Requester, Provider, and TBoard (which extends Serializable).
In the Requester (client) class, I instantiate an object of TBoard (TBoard board = new TBoard()).
I then send that object through the socket to my two clients, via an output stream.
The error I am getting is on the client-side, and it is: Exception in thread "main" java.lang.ClassCastException: java.lang.String
That's happening with:
board = (TBoard) in.readObject(); in:
do {
try {
board = (TBoard) in.readObject();
System.out.println(board.print_board());
} catch (ClassNotFoundException classNot) {
System.err.println("data received in unknown format");
}
My print_board() method in the TBoard class is meant to return a 2d array, but for right now (simplification purposes), I have the method returning the string "Hello"...
Does anyone know why this may be happening? I didn't want to bombard you all with code, but please let me know if posting any more may be helpful...
Thanks!
UPDATE:
Here is what I have going on (in more detail) with my Provider (server) class:
// 1. creating a server socket
providerSocket = new ServerSocket(20092);
// 2. Wait for connection
System.out.println("Waiting for connection...");
connection1 = providerSocket.accept();
System.out.println("Connection received from Player 1 " +
connection1.getInetAddress().getHostName());
connection2 = providerSocket.accept();
System.out.println("Connection received from Player 2 " + connection2.getInetAddress().getHostName());
// 3. get Input and Output streams
out = new ObjectOutputStream(connection1.getOutputStream());
out2 = new ObjectOutputStream(connection2.getOutputStream());
in = new ObjectInputStream(connection1.getInputStream());
out.writeObject("Player 1 has been connected successfully.");
in2 = new ObjectInputStream(connection2.getInputStream());
out2.writeObject("Player 2 has been connected successfully.");
out.flush();
out2.flush();
out.writeObject(board);
out2.writeObject(board);
So I am indeed sending a String in the streams before sending the last object (board). However, I am flushing out the streams beforehand. I also tried reset()'s after the flushes, and it still gave me the IllegalCastException...
IIRC, the class mentioned in the Exception is the one that was actually found, so in the code you're showing, the error would have to be here:
board = (TBoard) in.readObject();
And a String object instead of a TBoard being read from the stream.
Edit:
So you are sending strings in addition to the data. There's your problem. You either have to stop sending those strings, or read them on the receiving side before reading the data. Calling flush() is irrelevant to that - it just ensures that the Strings that you have already written to the stream are in fact sent over the connection and not kept in a buffer.
To investigate, I think the easiest would be to visualize (log or debug) the actual class that result from in.readObject(). Sample code:
Object o = in.readObject();
System.out.println("Object of class " + o.getClass().getName() + " is " + o);
There are a couple of possibilities. Assuming you are using ObjectOutputStream (which I think you are), it's possible that the error is arising because you are not fully serializing each object. ObjectOutputStream will try and hold of resending if you don't reset the stream each time.
I would try the following:
1) make sure you flush() and close() the sockets at the appropriate times
2) try calling reset() after each object is sent.
3) check that you are sending and receiving the same object type, just in case.
best of luck.

Categories