Must server & client have reverse sequence of claiming ObjectOutputStream & ObjectInputStream? - java

In my experiment,
if Server has this:
ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
then client side has to do this, in the opposite order:
ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
Otherwise server and client will deadlock.
What's the reason for this? and is there a formal API spec for it?

Yes. I see how this might happen. The javadoc for the ObjectInputStream constructor says this:
"Creates an ObjectInputStream that reads from the specified InputStream. A serialization stream header is read from the stream and verified. This constructor will block until the corresponding ObjectOutputStream has written and flushed the header."
So if both the client and the server construct their ObjectInputStream before their ObjectOutputStream, then both will block waiting for the other end to send the serialization stream header.
Note that this is happening at the object stream level, not the socket or bytestream levels. If you are doing simple byte or character or "data" I/O over a socket, you don't need to worry about the order in which the streams are constructed.
Also not, that this is not a problem if you have separate threads on (both) the client and server sides to do the reading and writing. All things being equal, that is probably a better architecture because it allows the client/server communication over the socket to be "full duplex".

Related

DataInputStream stuck when initialized

I have been trying to send a byte[] array across my client / server application using Sockets, DataInputStream and DataOutputStream, but on the server side, the program just gets stuck when I try to initialise the DataInputStream.
Here is the code on the client side (it works fine):
DataOutputStream datas = new DataOutputStream(connection.getOutputStream());
datas.flush();
byte[] send = identityKeyPair.serialize();
datas.write(send);
datas.flush();
Here is the code on the server side:
reader = new BufferedReader(new InputStreamReader(connection.getInputStream()) );
sender = new PrintWriter(connection.getOutputStream());
newUser = new BasicUserData();
System.out.println("New registration from: " + connection.getInetAddress());
System.out.println("Data:");
String un = reader.readLine();
newUser.USERNAME = un;
System.out.println(newUser.USERNAME);
String pw = reader.readLine();
newUser.PASSWORD = pw;
System.out.println(newUser.PASSWORD);
DataOutputStream dataout = new DataOutputStream(connection.getOutputStream());
System.out.println("Opened data output stream");
DataInputStream receiver = new DataInputStream(connection.getInputStream());
//It gets stuck here, and the program doesn't read anything further
receiver.read();
byte[] id = receiver.readAllBytes();
System.out.println("Opened data input stream");
You are using both connection.getInputStream() and connection.getOutputStream() in two different ways. You should use one and only one way of reading from and writing to streams, don't mix multiple ways.
When you execute reader.readLine(), the BufferedReader called reader will read up-to 8192 characters from the input stream into its buffer, likely consuming all bytes your client has written. This means that when you construct your DataInputStream around that same input stream and try to read it, there is no data available to read, causing the receiver.read() to block waiting for data. That data is never received as your client has sent all its data, which is now buffered in reader.
In addition, unless your client has closed its output stream, InputStream.readAllBytes() will block indefinitely anyway, because it is only finished when the end-of-stream has been reached. And for socket communication, that only happens when the other side closed its output stream.
Change your code so there is only one way of writing data (though not relevant here), and one way of reading data. In addition, you should establish clearly how you need to read and write data in a protocol, so to avoid consuming too much data at the wrong point, and to know how much data you need to read when.
Of course it does nothing but wait as specified in the javadoc a call to DataInputStream#read() blocks the current thread until data can be read from the input stream.
Your reader = BufferedReader(...) uses the same underlying InputStream which means the all the data the client sent is most likely already consumed by the 'login' logic.
Since neither the client nor the server close their respective streams no EOF is emitted either which leads to the stream 'just dangling' around waiting for more data.
Unless your client sends more data the server will wait eternally.
There are two solutions for your issue.
Either thread you application so that the 'await input' logic is in it's own thread or take a look at javas NIO package (more precisely Channels and Selectors)

Sockets and Streams in Java

I have build a client-server application and the two are communicating via sockets and streams.
My server creates these streams:
this.out = new DataOutputStream(sock.getOutputStream());
this.in = new DataInputStream(sock.getInputStream());
this.bufread = new BufferedReader(newInputStreamReader(sock.getInputStream()));
and then reads from the InputStream like that:
type = this.in.readByte();
String name = this.bufread.readLine();
Lastly the client writes to the OutputStream like this:
DataOutputStream out = new DataOutputStream(MyClient.getOutputStream());
out.writeByte(17);
out.writeBytes("value\n");
I am sending bytes from my client and the server is reading bytes. If I send chars, ints or anything else from the client will it still be read as bytes from the server? Does the specific function used ensure the type of data read?
You cannot wrap the same InputStream in two different objects (a DataInputStream and an InputStreamReader). They do not know about each other and will interfere with each other’s operation.
Wrap your socket’s InputStream in one object. Since you need to read raw bytes, a DataInputStream makes the most sense.
As you may have seen, you cannot use the readLine method of DataInputStream, because it is deprecated. Do not attempt to ignore that deprecation and use it anyway; it is deprecated for a reason, namely because it does not handle characters properly.
Ideally, you should use the readUTF method instead, but you must make sure that the server is sending character data using DataOutputStream.writeUTF for this to work.

ObjectInputStream blocking in readObject()

I'm writing a client/server application in which server sends serializable objects to client via ObjectOutputStream (i'll call it oos from now on) and client gets 'em with ObjectInputStream ("ois" from now on).
Now, since the server is executed first, I initialize the oos first. As it should be. Here's how I initialize it:
OutputStream outStream=incoming.getOutputStream();
DataOutputStream outToClient=new DataOutputStream(outStream);
outToClient.flush();
ObjectOutputStream oos = new ObjectOutputStream(outStream);
oos.flush();
Then I start the client and I initialize the ois with these line:
inStream = clientSocket.getInputStream();
ObjectInputStream ois = new ObjectInputStream(inStream);
From now on, the server side will send many objects on the same stream this way:
oos.writeUnshared(wishes);
in a while loop.
The problem is: when I execute this goddamn code on my pc alone, it's all good. No problems at all. When I try on two different machines, deadlock appears. The client side remains hanging on this line forever:
tempWishes = (ArrayList<String>) ois.readObject();
Feel free to ask more details. I didn't share the whole client and server code because it's like 500 lines of code.
This looks suspicious:
DataOutputStream outToClient=new DataOutputStream(outStream);
ObjectOutputStream oos = new ObjectOutputStream(outStream);
Both outToClient and oos are writing to the same underlying stream. This is likely to cause weirdness.
#EJP's suggestion that you remove the DataOutputStream is a good one because the DataOutputStream class isn't what you're after (since you're writing objects), and you almost certainly want a single chain of OutputStreams.
Have you tried using ois.readUnshared() instead of ois.readObject(). Even though it may no be the whole issue, it may be some other, it's good practice to couple write and reads.
Let me know if this fixed it.

How can a server know when the message it receives is actally over?

I'm trying to implement a server and it does something like this when it receives a message:
try{
ObjectInputStream is = new ObjectInputStream(clientSocket.getInputStream());
String message = (String)is.readObject();
ActivateCommand(message,clientSocket);
is.close();
}
and the ActivateCommand:
private void ActivateEwolfCommand(String msg, Socket clientSocket) throws IOException
{
ObjectOutputStream os = new ObjectOutputStream(clientSocket.getOutputStream());
Gson gsonObject = new Gson();
.
//code which makes a Json string
.
os.writeObject(json);
os.close();
}
now, when i tested it with sending a message to the local host with a junit test it worked. But when tried connecting to the server from a C# client, the client connected but the server throw an EOF exception when getting to the point of clientSocket.getInputStream().
I'm guessing it happens because the server did not know when the message is suppose to end but i don't know if thats really the case and if it is, then how can i fix it?
When there is no more data available on the InputStream to read() - that basically is what causes an EOF. How much data is available is determined by the client - the data that it writes to the Socket's OutputStream on its side appears as such on the InputStream of Socket of the server side. You can call InputStream.available() to get an estimate of number of bytes that can be still read().
However your code is trying to read an Object using an ObjectInputStream - this class has its own protocol to read a serialized byte stream and convert that to an object - if it does not find the bytes to complete the task this can throw the EOF exception. If your client is in C# - the format of bytes this writes for a serialized object will definitely not be the same as expected by the ObjectInputStream on the server side.
This is why it's a bad idea to create your own client-server protocol with a socket and object streams. Many people have spent many years bringing you, oh, well:
SOAP
REST
RMI
Hessian
CORBA
Thrift
and the multitude of other protocols out there. Surely one of them, if not 5 or 6, is good enough to solve your problem, including all issues of framing.
If you want to send strings over a socket, then an ObjectInputStream or ObjectOutputStream isn't the right stream implementation. These stream implementations use Java object serialization. Even if you serialize String instances, the resulting bytes are not the same as plain string to byte conversion with the appropriate character encoding.
And a C# application doesn't understand Java serialization at all.
Consider using a PrintWriter to write strings to your stream and a BufferedReader for reading.
PrintWriter writer = new PrintWriter(new OutputStreamWriter(clientSocket.getOutputStream(), "UTF-8"));
writer.println(...);
BufferedReader reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream(), "UTF-8"));
String line = reader.readLine();
Then you can read and write strings line by line.
This is only a starting point. If you want to implement your own protocol you have to pay attention to some more points. As an example you can read the specifications for some TCP protocols like POP3, FTP or HTTP 1.0.

writing an object to socket

I have got a problem in here...!
I want to write a program in which I have to pass some data and packet_no of that data...
So, I am creating an class Packet. I want to send the an Packet object through the OutputStream of the Socket.
How do I achieve this?
Thanks
The thing, that you need, is called an ObjectOutputStream. it is created from the regular OutputStream. At the reciever side you will need the appropriate ObjectInputStream. Your object and all of it's fields must implement Serializable interface.
Example code:
OutputStream os = socket.getOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(os);
oos.writeObject(p);

Categories

Resources