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.
Related
I have a piece of code
...
InputStream inputStream = new BufferedInputStream(new ByteArrayInputStream("test".getBytes()));
...
and this line makes string "test" an input for an InputStream, however this is a static InputStream.
is there any way without a Scanner, System.in or user external input to make this InputStream dynamic
what I need is something like this
...
InputStream inputStream = new BufferedInputStream(new
ByteArrayInputStream(generateContinuousDynamicString().getBytes()));
// So, basically input stream will be blocked until generateContinuousDynamicString()
// returns a result?
...
I've tried something like this
private static byte[] generateContinuousDynamicString(String s) {
String t = "";
// here comes the realization
// that the source for an input stream
// cannot be generated dynamically on the
// fly it only can be read from already
// existing (fully generated and available
// resource). Am I right? Otherwise how
// can I adjust this method in such a way that
// input stream would continuously have a new
// string to read from?
for (int i = 0; i < 1000; i++){
t += "<str>"+s+i+"</str>";
}
return ("<test>"+t+"</test>").getBytes();
}
So, if we have
...
InputStream inputStream = new BufferedInputStream(readFromADatabaseStream());
...
This is also not dynamic input stream as a resource is already in a database.
You want a pipe. Specifically, you want one of the following pairs of classes:
PipedInputStream and PipedOutputStream
PipedReader and PipedWriter
Your question asks for an InputStream, but since you’re dealing with text, you probably should use a Reader, which is intended for characters. In particular, note that getBytes() will return different values on Windows systems compared to non-Windows systems, for any String with non-ASCII characters. Using a Reader and Writer will remove the need to worry about that.
Either way, the approach is the same: create the readable end of the pipe, then create and feed the writable end of the pipe in another thread.
Using a PipedReader and PipedWriter:
PipedReader pipedReader = new PipedReader();
Reader reader = new BufferedReader(pipedReader);
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<?> pipeFeeder = executor.submit(
() -> generateContinuousDynamicString(pipedReader));
// ...
private Void generateContinuousDynamicString(PipedReader pipedReader)
throws IOException {
try (Writer writer = new PipedWriter(pipedReader)) {
writer.write("<test>");
for (int i = 0; i < 1000; i++) {
writer.write("<str>" + i + "</str>");
}
writer.write("</test>");
}
return null;
}
Using a PipedInputStream and PipedOutputStream:
PipedInputStream pipedInputStream = new PipedInputStream();
InputStream inputStream = new BufferedInputStream(pipedInputStream);
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<?> pipeFeeder = executor.submit(
() -> generateContinuousDynamicString(pipedInputStream));
// ...
private Void generateContinuousDynamicString(PipedInputStream pipedInputStream)
throws IOException {
Charset charset = StandardCharsets.UTF_8;
try (Writer writer = new OutputStreamWriter(
new PipedInputStream(pipedinputStream),
StandardCharsets.UTF_8)) {
writer.write("<test>");
for (int i = 0; i < 1000; i++) {
writer.write("<str>" + i + "</str>");
}
writer.write("</test>");
}
return null;
}
Sure. But you have a bit of an issue: Whatever code is generating the endless stream of dynamic data cannot just be in the method that 'returns the inputstream' just by itself, that's what your realisation is about.
You have two major options:
Threads
Instead, you could fire off a thread which is continually generating data. Note that whatever it 'generates' needs to be cached; this is not a good fit if, say, you want to dynamically generate an inputstream that just serves up an endless amount of 0 bytes, for example. It's a good fit if the data is coming from, say, a USB connected arduino that from time to time sends information about a temperature sensor that it's connected to. Note that you need the thread to store the data it receives someplace, and then have an inputstream that will 'pull' from this queue of data you're making. To make an inputstream that pulls from a queue, see the next section. As this will involve threads, use something from java.util.concurrent, such as ArrayBlockingQueue - this has the double benefit that you won't get infinite buffers, either (the act of putting something in the buffer will block if the buffer is full).
subclassing
What you can also do is take the code that can generate new values, but, put it in an envelope - a thing you can pass around. You want to make some code, but not run it - you want to run that later, when the thing you hand the inputstream to, calls .read().
One easy way to do that, is to extend InputStream - and then implement your own zero method. Looks something like this:
class InfiniteZeroesInputStream extends InputStream {
public int read() {
return 0;
}
}
It's that simple. Given:
try (InputStream in = new InfiniteZeroesInputStream()) {
in.read(); // returns 0.. and will always do so.
byte[] b = new byte[65536];
in.read(b); // fills the whole array with zeroes.
}
I'm trying to create a game using only two classes - ServerSocket and Socket. Everything must be at the TCP (not UDP), while architecture is necessarily P2P. The way this game works is that one player chooses a number, then the other and it starts with one of them (no matter which one) counting down. I came across a problem. I establish a connection between two clients and both may enter the selected number. I do not know why I can not send this number to another client. Is the problem that Socket can not send and receive messages at the same time? I've read that there is a possibility to do this using two separate Threads (one receives data, the other sends), but I do not know how exactly.
#Override
public void run() {
BufferedReader br = new BufferedReader(new InputStreamReader(System. in ));
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
System.out.println("PICK A NUMBER:");
while (!br.ready()) {
Thread.sleep(500);
}
Integer numberGamePicked = Integer.parseInt(br.readLine());
Thread.sleep(500);
out.println(numberGamePicked);
Thread.sleep(1000);
BufferedReader in =new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
int whatOpponentSend = Integer.parseInt( in .readLine());
System.out.println("RECEIVED " + whatOpponentSend);
}
Of course, up to this point everything is in the run() method. Is the problem that both of them execute the same code at the same time?
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 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.
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.