I have a fairly complex project that boils down to a simple Client / Server communicating through object streams.
Everything works flawlessly for two consecutive connections (I connect once, work, disconnect, then connect again, work, and disconnect). The client connects, does its business, and then closes. The server successfully closes both the object output stream and the socket, with no IO errors.
When I try to connect a third time, the connection appears to go through (the ServerSocket.accept() method goes through and an ObjectOutputStream is successfully created). No data is passed, however. The inputStream.readUnshared() method simply blocks.
I have taken the following memory precautions:
When it comes time to close the sockets, all running threads are stopped, and all objects are nulled out.
After every writeUnshared() method
call, the ObjectOutputBuffer is
flushed and reset.
Has anyone encountered a similar problem, or does anyone have any suggestions? I'm afraid my project is rather large, and so copying code is problematic.
The project boils down to this:
SERVER MAIN
ServerSocket serverSocket = new ServerSocket(port);
while (true) {
new WorkThread(serverSocket.accept()).start();
}
WORK THREAD (SERVER)
public void run() {
ObjectInputBuffer inputBuffer = new ObjectInputBuffer(new BufferedInputStream(socket.getInputStream()));
while (running) {
try {
Object myObject = inputBuffer.readUnshared();
// do work is not specified in this sample
doWork(myObject);
} catch (IOException e) {
running = false;
}
}
try {
inputBuffer.close();
socket.close();
} catch (Exception e) {
System.out.println("Could not close.");
}
}
CLIENT
public Client() {
Object myObject;
Socket mySocket = new Socket(address, port);
try {
ObjectOutputBuffer output = new ObjectOutputBuffer(new BufferedOutputStream(mySocket.getOutputStream()));
output.reset();
output.flush();
} catch (Exception e) {
System.out.println("Could not get an input.");
mySocket.close();
return;
}
// get object data is not specified in this sample. it simply returns a serializable object
myObject = getObjectData();
while (myObject != null) {
try {
output.writeUnshared(myObject);
output.reset();
output.flush();
} catch (Exception e) {
e.printStackTrace();
break;
} // catch
} // while
try {
output.close();
socket.close();
} catch (Exception e) {
System.out.println("Could not close.");
}
}
Thank you to everyone who may be able to help!
(1) What's ObjectInputBuffer and ObjectOutputBuffer? Did you mean ObjectInputStream & ObjectOutputStream?
(2) If so, calling reset() immediately after creating the ObjectOutputStream is just a waste of time and bandwidth.
(3) Why are you printing 'could not get an input' on an exception creating an output stream?
(4) When you get an exception you should always print its message - don't completely substitute it with your own, that's just throwing away useful information.
(5) You are assuming that any IOException when reading means the end of the stream. Only EOFException means that. Any other IOException should be printed or logged. Clearly you are getting some other exception here and ignoring it.
(6) Why do you keep sending the same object?
From ObjectInputStream API for readUnshared():
Reads an "unshared" object from the
ObjectInputStream. This method is
identical to readObject, except that
it prevents subsequent calls to
readObject and readUnshared from
returning additional references to the
deserialized instance obtained via
this call.
Could this be the problem? Use readObject() instead.
Related
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.
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.
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.
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.
I was trying to get some networking going in my app, but i encountered some issues. It seems that I cant write to the OutputStream object. Though my server recieves the connection, it does not recieve any data. I've tried using Writer, DataOutputStream among others. none seemed to work.
My app uses asynctasks that call this object with a Socket object and a message. (The socket object has already been used to set Streams after initialisation using the setStreams method.)
can someone please try and find the problem? I will be very thankful.
public class NetworkingUtils {
private OutputStream out = null;
private InputStream in = null;
//set streams
public void setStreams(Socket sock){
if (sock.isConnected()) {
try {
this.out = (OutputStream) sock.getOutputStream();
this.in = (InputStream) sock.getInputStream();
} catch (Throwable e) {
Log.d("SOCKET", "FAILED TO SET STREAMS");
e.printStackTrace();
}
}
}
//send \n terminated messages to pre defined socket
public void sendMessage(Socket sock, String message) throws Throwable {
if (sock.isConnected()) {
try {
this.out.write(message.getBytes());
Log.d("SOCKET","WRITING COMPLETE. " + message);
} catch (Throwable e) {
throw e;
}
}
}
public String recvMessage(Socket sock) throws Throwable {
//receives \n terminated message from pre defined socket
String answer = null;
if (sock.isConnected()){
try{
answer = this.convertStreamToString(this.in);
Log.d("SOCKET","READING COMPLETE");
}
catch (Throwable e){
Log.d("socket",e.getLocalizedMessage());
throw e;
}
}
else{
Log.d("socket","is not connected!!!");
}
if (answer.length() == 0){
//empty string answer from server
throw new IOException();
}
else {
return answer;
}
}
private String convertStreamToString(java.io.InputStream is) {
java.util.Scanner s = null;
try{
s = new java.util.Scanner(is).useDelimiter("\r\n");}
catch (Throwable e){
e.printStackTrace();
}
return s.hasNext() ? s.next() : "";
}
}
I can only see one client-side that might cause this ... and I'm doubtful about it. (That is to say: try this, just in case it makes a differences, but I don't think it will.)
this.out.write(message.getBytes());
Log.d("SOCKET","WRITING COMPLETE. " + message);
The potential problem is that if out is a "buffered" stream, then a write may only result in the bytes being written to the buffer. It may be necessary to call this.out.flush() to "push" to the server.
But I am doubtful it will help, because (to my knowledge) a socket output stream isn't buffered in Java. I think it is more likely that the real problem is on the server side.
If you are stumped with figuring out which side the problem is occuring, I suggest you try using a network monitoring / packet sniffing tool (on the server side) to check if the data is reaching the server host.
While I have your attention, your exception code is really, really bad.
Don't declare methods as throws Throwable (or throws Exception). That basically says "this method may throw ANY exception, and I'm not telling you which one". When you do that, the caller code has to cope with any exception, which is basically impossible to do intelligently.
What you should do is to declare the method as throwing the checked exceptions that the code can throw. For example, in your case, IOException is probably sufficient.
It is not a good idea to catch an exception, log it, and then rethrow it. Why? Because further up the stack there are probably other methods that will see the exception. They can't know if the exception has already been logged or not. So should they log it (possibly resulting in duplicate logs events for the same problem) or not (possibly resulting in the exception going unlogged.)
Don't throw exceptions without a message:
throw new IOException();
It is lazy. You should always include a simple message that can (at least) be grep'd or googled for.
In addition, your testing of Socket.isConnected() all over the place is unnecessary. According to the javadoc:
Returns: true if the socket was successfuly connected to a server
Note: Closing a socket doesn't clear its connection state, which means
this method will return true for a closed socket (see isClosed()) if
it was successfuly connected prior to being closed.
So repeatedly testing isConnected is nugatory. If it returns true once, it will will always return true from then on.
Even the initial isConnected test in setStreams is doubtful. I'd just call getInputStream without testing, and rely on the Socket API throwing an IOException if the socket is in the wrong state.
You're effectively reading lines with that obscure Scanner usage, but you're not writing lines. So the scanner will block until a line terminator or EOS arrives.
You need to append a line terminator when sending.