I ran into a problem while using input/output streams in Java. My thought was to have a DataInputStream to handle receiving text and a PrintStream to pass messages to the server from the server and object(output/input)streams to handle passing piece movements and current board image.
My problem is that the code hangs while it is trying to create the ObjectInputStream in the code below. Is this because I am trying to have multiple input and output streams? If so is there any possible fix I could use?
Socket sock = new Socket("127.0.0.1", 1716);
input = new DataInputStream(sock.getInputStream());
printer = new PrintStream(sock.getOutputStream());
System.out.println("Test 1");
zelda = new ObjectInputStream(sock.getInputStream());
System.out.println("Test 2");
link = new ObjectOutputStream(sock.getOutputStream());
System.out.println("Test 3");
I have a lot of Legend of Zelda references in my server source code and the code is rather large. The previous source code is for the client and although the server connects here is where I call ObjectOutputStream.
ObjectOutputStream ganandorf;
for(int i = 0; i < clients.size(); i++)
{
try
{
ganandorf = new ObjectOutputStream(clients.get(i).getOutputStream());
ganandorf.write(1);
ganandorf.flush();
ganandorf.writeObject(something);
ganandorf.flush();
}
Don't try to use two different kinds of streams/readers/writers on the same underlying connection. You will encounter buffering issues at both ends that make it basically impossible.
I would use ObjectInputStream and ObjectOutputStream and just write objects.
The constructor of ObjectInputStream blocks until it receives the header that is written by the constructor of ObjectOutputStream, so if you are constructing both you must construct the ObjectOutputStream first. You don't need to write anything and you don't need to flush it either, it does that itself.
I think you can only ask for 1 inputStream reference:
InputStream baseInputStream = sock.getInputStream();
input = new DataInputStream(baseInputStream);
zelda = new ObjectInputStream(baseInputStream);
same goes for outputStreams
I never found out what happened with ObjectInputStream, but I switched to DataInputStream and I'm currently modifying my code so it sends the piece name, x location, and y location in one string that will get broken up at the client and the board will be modified accordingly
Open a socket on a different port and use that to create new streams.
Related
I've been trying to send more than one instance of Properties over a socket connection using PrintWriter/BufferedWriter for sending and InputStreamReader for reading, all sent and received over loop.
Sender:
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
for (int i = 0; i < vector.size(); i++) {
Properties mail = (Properties) vec.get(i);
mail.store(bw, line);
bw.newLine();
bw.flush();
}
Receiver:
ireader = new InputStreamReader(socket.getInputStream());
Properties[] mails=new Properties[c];
for (int i = 0; i < c; i++) {
Properties p;// = new Properties();
mails[i] = new Properties();
mails[i].load(ireader);
}
But I'm only receiving the last Properties object sent by the receiver only after its entire loop is done with. That'd mean the receiver is loading until the socket eventually closes. The documentation does say that for load(), the underlying reader is left open after returning, but I guess I've missed the part explaining 'when' it actually returns. How can I read multiple Properties with one stream?
Let's suppose you have 2 Properties instances:
A:
a=b
c=d
B:
e=f
g=h
If you send these two properties instances, what will be sent on the wire will be:
a=b
c=d
e=f
g=h
And the receiver doesn't have any way to know that this constitutes two different instances. It reads all the properties until the end of the stream, and stores all the read properties in a single object.
You need to find another protocol to send those two objects.
First of all, this is a homework problem. That being said, I'm stuck. Googling for java Properties over Sockets results in a lot of irrelevant things.
I'm trying to transfer a Properties object over a socket. The API says it can be done with a Stream or a Writer/Reader, but I can't get it to work. I can do it manually, that is, if I read the file line by line and pass it through a PrintWriter.
On the client side I've got roughly:
socket = new Socket(host, port);
outStream = socket.getOutputStream();
out = new PrintWriter(outStream, true);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
reader = new BufferedReader(new FileReader(file));
...
props.load(reader);
props.store(out, null);
On the server side the receiving bits look like:
out = new PrintWriter(sock.getOutputStream(), true);
inStream = sock.getInputStream();
in = new BufferedReader( new InputStreamReader(inStream));
...
props.load(in); // hangs
// doesn't get to code here...
In this case it hangs at the props.load(in). Instead of doing props.load(in), I read it in line by line to make sure props.store(out, null) was working, and the data looks like its being transferred.
Is there something about load/store I don't understand, or is it an issue with the Stream/Writer/Reader?
I think this will answer this question as well as How do I recognize EOF in Java Sockets? and What can I send to an InputStream to signify EOF has been reached?
I had a similar problem; my dilemma was that I had a client/server request-response protocol where one of the requests included a stream sent from the client side using clientProps.store(). The corresponding serverProps.load() on the server side never returns because it needs to see the "end-of-file" - which in Java means the client has to close it's stream; resulting in the socket connection closing. The unwanted result was that, not only could I not keep the socket open for indefinite request-response exchanges, I couldn't even keep it open for the server to send its reply.
I hated Java for making me do that, even more because the documentation for Properties.load() says:
The specified stream remains open after this method returns.
That could never happen if it's detecting end-of-file by seeing the stream close!! Anyway, now, I still love Java because it allowed me to use this solution (might not be useful if you have any special encoding or localization of the data you are streaming):
I used this on the client side:
PrintWriter toServer;
Properties clientProps = new Properties();
// ... code to populate the properties and to
// construct toServer from the socket ...
clientProps.store(toServer, null);
toServer.write('\u001A'); // this is an old-school ASCII end-of-file
toServer.flush();
On the server side I extended Reader to detect the 1A and return -1 (so that the serverProps.load() learns about the end-of-file in the normal way (by seeing -1 returned from a call to read()), but below that, the stream and the socket stay open.
BufferedReader fromClient;
Properties serverProps = new Properties();
// ... code to construct fromClient from the socket ...
serverProps.load (new PropReader (fromClient));
/////
private static class PropReader extends Reader {
BufferedReader src;
boolean eof=false;
private PropReader(BufferedReader fromClient) {
super();
src=fromClient;
}
#Override
public int read(char[] cbuf, int off, int len) throws IOException {
int inCount;
if (!eof) {
inCount = src.read(cbuf, off, len);
if (inCount > 0) {
// we read a buffer... look at the end for the EOF that the client used to mark the end of file
if (cbuf[off+inCount-1] == '\u001A') {
--inCount; // don't send eof with the data
eof = true; // next time... we'll return -1
}
}
} else {
inCount = -1;
}
return inCount;
}
#Override
public void close() throws IOException {
src.close();
}
I am developing a GUI program to use in a client/server system that will save data in a Vector. I have an ObjectOutputStream and ObjectInputStream that is created when I make the connection, however I am not sure how to pass it into the new class when i try to open one up. In my Startup class I have a Serializable object (Message m) that is created and passed into different classes to have different fields modified, as well as the connection gets established between the client and server
In my Startup class I have this code...
m.yourName = tmyName.getText();
m.department = tdepartment.getText();
if (m.yourName != null && m.department != null) {
client = new Socket(server, port);
oout = new ObjectOutputStream(client.getOutputStream());
oin = new ObjectInputStream(client.getInputStream());
toutput.setText("Connected");
oout.writeObject(m);
new WhatToDo (m, oout, oin);
}
In the WhatToDo class i have this code...
Message m;
ObjectOutputStream oout;
ObjectInputStream oin;
public WhatToDo(Message a, ObjectOutputStream oout2, ObjectInputStream oin2){
m = new Message();
m = a;
// this is what i'm unsure about and need help with
oout = oout2; //but need to construct oout first
oin = oin2; //but need to construct oin first
}
If i do the new ObjectOutputStream and ObjectInputStream like I did in Startup, i will create a new connection to the server. I wish to use the existing Streams created in Startup in WhatToDo. Thank you for your help in advance!
I'm using an ActionListener with button presses, so the streams will need to be saved in the constructor for later use in the ActionListener.
I wish to use the existing Streams
That is exactly what your code does now. Your comments about 'but need to construct' are incorrect.
I am feeling really stupid right now guys.... basically I am connecting over TCP on a local machine... and when I try to make the In/out streams at the client it wont get passed creating the object input stream. What gives? This stops after printing 2... no exceptions or anything... This isn't the first time I've used this class which is partialy why I am puzzled.
try {
System.out.println("1");
mySocket = new Socket("localhost", 11311);
System.out.println("12");
oos = new ObjectOutputStream(mySocket.getOutputStream());
System.out.println("2");
ois = new ObjectInputStream(mySocket.getInputStream());
System.out.println("13");
} catch (Exception e) {
e.printStackTrace();
}
From the specification of ObjectInputStream:
This constructor will block until the corresponding ObjectOutputStream
has written and flushed the header.
(For future readers:) I had the same problem because i made a silly change in server program and didn't test it for a long time then i was confused about why program is locked.
ServerSocket accepts the connection (responderSocket = serverSock.accept();) then suddenly for a inapropriate if (The silly change i mentioned!) program jumps out of the thread and because i didn't add a finally block to close streams and sockets the socket was left abandoned w/o sending or recieving anything (even stream headers). So in client side program there was no stream header (When i debbugged The code i saw that the last function executed before lock was:
public ObjectInputStream(InputStream in) throws IOException {
verifySubclass();
bin = new BlockDataInputStream(in);
handles = new HandleTable(10);
vlist = new ValidationList();
enableOverride = false;
readStreamHeader(); //// <== This function
bin.setBlockDataMode(true);
}
readStreamHeader();)
So be careful about what happens in server side, maybe problem isn't where you expecting it!
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.