socket closing early on multiple transfers - java

I'm trying to send an object over the network to another computer (or the same computer) and then have said computer send an object back.
On the sending computer, I send the object and receive the returned object:
ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
objectOutputStream.writeObject(object);
Object returnedObject;
socket.setSoTimeout(timeout);
try (ObjectInputStream ois = new ObjectInputStream(socket.getInputStream())) {
returnedObject = (Object) ois.readObject();
}
return returnedObject;
On the receiving computer, I receive the object:
Object object;
socket.setSoTimeout(timeout);
try (ObjectInputStream ois = new ObjectInputStream(socket.getInputStream())) {
object = (Object) ois.readObject();
}
return object;
and then send an object back:
socket.setSoTimeout(timeout);
ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
objectOutputStream.writeObject(object);
The error I get back is:
SEVERE: null java.net.SocketException: Socket is closed at
java.net.Socket.setSoTimeout(Socket.java:1137) at
and it occurs while attempting to send an object back on the receiving computer.
The socket on the sending computer is using the same address and port as the socket on the receiving computer.

This exception means that you closed the socket and then continued to use it. Specifically, you closed the ObjectInputStream at the end of the try-with-resources block where it is declared. That closes the other stream of the socket and the socket itself.
Don't use new object streams per transfer. Use the same ones for the life of the socket, at both ends.

You are using a very small-scoped try-with-resources:
try (ObjectInputStream ois = new ObjectInputStream(socket.getInputStream())) {
returnedObject = (Object) ois.readObject();
}
This code is interpreted as:
Get the input stream and build an ObjectInputStream around it.
Read an object from the object stream
Close the ObjectInputStream.
When you close the ObjectInputStream it automatically closes the InputStream that backs it, which is the socket's input stream. And the documentation of getInputStream says:
Closing the returned InputStream will close the associated socket.
You should make sure the try-with-resources has a bigger scope that covers the entire lifetime of the socket, or avoid using try-with-resources and make sure you close the ObjecInputStream properly when you are done with it or when there is an error.

Related

Error in receiving ObjectInputStream

I am trying to create a client server program where I'm sending an object from client and receiving the object at the server continuously in the while loop.
Client code:
ObjectOutputStream oos = null;
while(true){
WorkerMessageToMaster message = new WorkerMessageToMaster(WorkerTasksStatus.getTaskStatusMap(), WorkerTasksStatus.getTaskStatusReduce());
oos = new ObjectOutputStream(taskManagerSocket.getOutputStream());
oos.writeObject(message);
oos.flush();
Thread.sleep(1000);
}
Server code:
ObjectInputStream ois = null;
while (true ) {
ois = new ObjectInputStream(clientSocket.getInputStream());
WorkerMessageToMaster taskMapObject = (WorkerMessageToMaster)ois.readObject();
System.out.println("Connection from: "+clientSocket.getInetAddress().getHostAddress().toString());
}
When I try to run this code on my local system It runs normally, but when I try to run the client and server in different machines(different Ips) I get the following error.
java.io.StreamCorruptedException: invalid stream header: 74000432
at java.io.ObjectInputStream.readStreamHeader(ObjectInputStream.java:804)
at java.io.ObjectInputStream.<init>(ObjectInputStream.java:299)
at master.MasterAnalyzer.heartBeat(MasterAnalyzer.java:58)
at master.MasterAnalyzer.run(MasterAnalyzer.java:80)
at java.lang.Thread.run(Thread.java:745)
I am confused at this erratic behavior as Im sending the stream through the client socket established with the server in a while loop and receiving it on the same socket connection accepted at the server and It seems to be working fine on local host.
Thank you for your help
You create a new stream for each object. Only create one output and one input stream. Object streams send header data which is maybe corrupted when you create a new stream.

Using resources of try-with-resources outside try

I'm using SocketChannel to send message between a server and a client. Once a client connects with a server, the server opens the InputStreams and OutputStream in a try-with-resources try, to receive messages from the client and send messages to the client, like so:
try (ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
ObjectInputStream in = new ObjectInputStream(socket.getInputStream())) {}
I want to access out outside of the try. The try contains a while loop that repeatedly checks if messages has arrived on in, which works fine.
I tried setting a global variable, say global_out, by doing:
ObjectOutputStream global_out;
...
try (ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
ObjectInputStream in = new ObjectInputStream(socket.getInputStream())) {
setOut(out);
while(should_check) {
Object message = in.readObject();
//do something
}
}
And then I tried writing to this OutputStream, like so:
public void sendMessage(Object message) {
global_out.writeObject(message);
}
I only call sendMessage(Object) when should_ceck is true and test if global_out is null, which it isn't. However, sendMessage(Object) never returns. If global_out isn't null, it must have been set to something, so why can't the resources be used before the try-with-resources terminates?
Is there any way I can get around this?

Confused About Reading and Writing From Input Streams (Sockets)

I have a question about reading and writing from input streams related to a socket. For instance, I have
ServerSocket testie = new ServerSocket(0);
Socket putClient = new Socket("localhost",testie.getLocalPort());
InputStream is = putClient.getInputStream();
OutputStream os = putClient.getOutputStream();
os.write("testt".getBytes());
System.out.println(convertStreamToString(is));
but "testt" is oddly never printed. The method convertStreamToString is from
Read/convert an InputStream to a String
public static String convertStreamToString(java.io.InputStream is) {
java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A");
return s.hasNext() ? s.next() : "";
}
Is there some flaw in my understanding of streams and sockets. I thought that if you wrote to a socket's output stream you can retrieve it from its input stream? The method just hangs indefinitely.
If you write to a socket's output stream you can read from the remote socket's input stream. In your code you are writing to one side of the socket and then trying to read from that same side.
Unfortunately, you haven't even created the remote socket yet. The next thing you will want to do is call accept() on the ServerSocket. This will receive the connection from putClient and create a Socket. This new socket will be the server side socket. Essentially you will have the following:
//Server Thread
ServerSocket testie = new ServerSocket(0);
Socket remoteSocket = testie.accept();
remoteIs = remoteSocket.getInputStream();
remoteOs = remoteSocket.getOutputStream();
System.out.println(new Scanner(remoteIs).next());
//Client Thread
Socket putClient = new Socket("localhost",testie.getLocalPort());
InputStream is = putClient.getInputStream();
OutputStream os = putClient.getOutputStream();
os.write("testt\n".getBytes());
os.flush();
Notice that I said two different threads. The problem is that the call testie.accept() will block until it gets a connection. But also, new Socket("localhost",testie.getLocalPort()) will block until the connection is established. These calls can't be made on the same thread.
UPDATE:
It's probably worth pointing out that I'm not very confident in that convertStringToStream method. You might want to start with something simple like what I've fixed the above to (note the newline in the write call).

Invalid stream header 434B0005 from client to server

I've serialized some objects so I can convert them to byte arrays for a TCP packet. When I send the objects from the server program to the client program, there are no issues and it works fine. However, even though the code between the server and client is identical, when I try to send objects from the client to the server I get an invalid header.
Here are the objects I'm serializing:
public static byte[] serialize(Hand c) throws IOException
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(c);
return baos.toByteArray();
}
public static Hand deserialize(byte[] bytes) throws IOException, ClassNotFoundException
{
ByteArrayInputStream b = new ByteArrayInputStream(bytes);
ObjectInputStream o = new ObjectInputStream(b);
return (Hand) o.readObject();
}
and
public static byte[] serialize(Card c) throws IOException
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(c);
return baos.toByteArray();
}
public static Card deserialize(byte[] bytes) throws IOException, ClassNotFoundException
{
ByteArrayInputStream b = new ByteArrayInputStream(bytes);
ObjectInputStream o = new ObjectInputStream(b);
return (Card) o.readObject();
}
Those are both taken from the Server program, but the code for the serialization is identical between the server and the client; I important the Card class and the Hand class from the Server to the Client precisely to make sure errors like this wouldn't occur.
The server can convert a Card or a Hand to a byte[] and write it over a DataOutputStream to the client, and the client can receive the Card or Hand through a DataInputStream, deserialize it, and read it with no problem. When I try to send a Card or a Hand from the Client to the Server, however, very rarely it works and usually I get a
Exception in thread "main" java.io.StreamCorruptedException: invalid stream header: 434B0005
at java.io.ObjectInputStream.readStreamHeader(Unknown Source)
at java.io.ObjectInputStream.<init>(Unknown Source)
at Hand.deserialize(Hand.java:29)
at KoiKoi_TCP_Server.takeClientTurn(KoiKoi_TCP_Server.java:321)
at KoiKoi_TCP_Server.main(KoiKoi_TCP_Server.java:380)
where Hand.java.29 points at the line
ObjectInputStream o = new ObjectInputStream(b);
in the Hand deserialization method.
I understand that it's telling me that the header is invalid. I'm not sure how to fix it, because it only breaks going one direction and the code is identical. Suggestions?
I'm only sending a solitary object at a time, so I'm not initializing multiple ObjectInputStreams or anything.
I'm not initializing multiple ObjectOutputStreams or anything.
Yes you are. You are initializing a new ObjectOutputStream for every object, and then you're giving yourself the additional problem of knowing how many bytes to read in order to receive each object, and you're getting that wrong, so you're getting out of sync.
Get rid of all this. You don't need it. It is just adding problems. Just use a single ObjectOutputStream and ObjectInputStream, directly, for the life of the socket, constructed directly over the socket streams, and call writeObject() when you want to send an object, and readObject() when you want to read one. Two lines of code. Forget about the byte arrays and the ByteArray/DataInput/OutputStreams altogether.

Client Server sockets java.net.SocketException: Software caused connection abort: recv failed [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
java.net.SocketException: Software caused connection abort: recv failed
I'm trying to write a client server pair where the connection is live all day and the client waits for the server to send a message. The steps are:
Server opens port and listens for connection
Client connects in and waits for data
Some time later (maybe hours) the server sends data to the client
Client processes data and returns it to the server
Repeat steps 3 and 4
I can get steps 1-4 working, however if I try to repeat step 3 I get the error in the title.
This is my method on the client side:
private static void waitForInput(SSLSocket sslsocket) throws IOException {
do {
try {
ObjectInputStream ois = new ObjectInputStream(sslsocket.getInputStream());
ObjectOutputStream oos = new ObjectOutputStream(sslsocket.getOutputStream());
Object o = (Object) (ois.readObject());
// excluded code to process data
oos.flush();
oos.writeObject(o);
oos.reset();
}
catch(ClassNotFoundException e){
System.err.println(e.getMessage());
}
} while ( true );
}
The code fails on the 4th line, The first time around it blocks and waits until I get the next bit of data, but it doesn't work twice. What am I doing wrong?
Connection abort IOException is thrown when you are waiting to read from a socket that has been closed at the other end, check to see your server side code , if you are not accidentally closing the socket.
Also the server side code could be uploaded for deeper analysis, also try posting the stack trace, it will help analyzing.
You could move the declaration for ois and oos out of the do ... while loop, since there is no need to redeclare them everytime, might need a try ... catch around that.
private static void waitForInput(SSLSocket sslsocket) throws IOException {
ObjectInputStream ois = new ObjectInputStream(sslsocket.getInputStream());
ObjectOutputStream oos = new ObjectOutputStream(sslsocket.getOutputStream());
do {
try {
Object o = (Object) (ois.readObject());
// excluded code to process data
oos.writeObject(o);
oos.flush();
}
catch(ClassNotFoundException e){
System.err.println(e.getMessage());
}
} while ( true );
}
And I have removed the oos.reset(); and moved the oos.flush();
I believe that the problem is the oos.reset(); and i would never reset a connection that is supposed to be persistent for hours, or, at least part of it.
Besides there is already a ois for that connection and you don't need two of them.

Categories

Resources