Wrapping Piped Streams?

R

Ryan Stewart

Is there something about wrapping PipedInputStreams and/or
PipedOutputStreams? Specifically, I'm trying to wrap them with
ObjectInputStreams and ObjectOutputStreams. With this code:

ObjectOutputStream oos = new ObjectOutputStream(pipeOut);
ObjectInputStream ois = new ObjectInputStream(pipeIn);

The first line appears to work, but code execution stops at the second line.
No exceptions or anything. It just stops.

Here's an executable example in two public classes. The first class creates
an piped in and out and instantiates the second class, which connects to
them. The first class sends one byte on pipeOut then pauses and listens for
a reply. The second class listens for the byte from the first class,
multiplies it by five, and sends it back. It all works as expected. But if
you put in the Object streams there, it screws everything up. Anyone know
why?

// First class
import java.io.*;

public class TestOut {

public static void main(String[] args) {
try {
PipedInputStream pipeIn = new PipedInputStream();
PipedOutputStream pipeOut = new PipedOutputStream();
TestIn ti = new TestIn(pipeIn, pipeOut);
System.out.println("Wrapping...");
//ObjectOutputStream oos = new ObjectOutputStream(pipeOut);
//ObjectInputStream ois = new ObjectInputStream(pipeIn);
System.out.println("Done wrapping.");
ti.start();
pipeOut.write(5);
Thread.sleep(100);
int result = pipeIn.read();
System.out.println(result);
} catch (Exception e) {
e.printStackTrace();
}
}
}

// Second class
import java.io.*;

public class TestIn extends Thread {

PipedInputStream pipeIn;
PipedOutputStream pipeOut;

public TestIn(PipedInputStream pipeIn, PipedOutputStream pipeOut) {
try {
this.pipeIn = new PipedInputStream(pipeOut);
this.pipeOut = new PipedOutputStream(pipeIn);
} catch (Exception e) {
e.printStackTrace();
}
}

public void run() {
try {
System.out.println("Listening");
int data = pipeIn.read();
pipeOut.write(data * 5);
} catch (Exception e) {
e.printStackTrace();
}
}
}
 
C

Chris Smith

Ryan said:
Is there something about wrapping PipedInputStreams and/or
PipedOutputStreams? Specifically, I'm trying to wrap them with
ObjectInputStreams and ObjectOutputStreams. With this code:

ObjectOutputStream oos = new ObjectOutputStream(pipeOut);
ObjectInputStream ois = new ObjectInputStream(pipeIn);

The first line appears to work, but code execution stops at the second line.
No exceptions or anything. It just stops.

This isn't a problem with wrapping PipedInputStream. It's a problem
with when to create an ObjectInputStream. The constructor for
ObjectInputStream reads an initial handshake from its target stream
before continuing. (Similarly, ObjectOutputStream writes such a
handshake in its constructor.) If that initial handshake is not
available, it blocks until that handshake is available.

Since your sample code needs to start the second thread in order for the
data path to be complete, you are running into this problem.
ObjectOutputStream writes this handshake to its pipe, and it gets stored
in a buffer waiting for someone to read it. ObjectInputStream tries to
read the handshake from its stream, and blocks. Now you're
deadlocked... if the constructor for ObjectInputStream were ever to
return, a new thread would be started to make that handshake available
to the input stream, but the input stream isn't going to return until it
gets that handshake.

In short, the solution is to be sure you've done everything you need to
do to have an active writer for a stream *before* you build an
ObjectInputStream from it. In your case, it means start the thread
before you wrap the streams.

--
www.designacourse.com
The Easiest Way to Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
 
R

Ryan Stewart

Chris Smith said:
This isn't a problem with wrapping PipedInputStream. It's a problem
with when to create an ObjectInputStream. The constructor for
ObjectInputStream reads an initial handshake from its target stream
before continuing. (Similarly, ObjectOutputStream writes such a
handshake in its constructor.) If that initial handshake is not
available, it blocks until that handshake is available.

Since your sample code needs to start the second thread in order for the
data path to be complete, you are running into this problem.
ObjectOutputStream writes this handshake to its pipe, and it gets stored
in a buffer waiting for someone to read it. ObjectInputStream tries to
read the handshake from its stream, and blocks. Now you're
deadlocked... if the constructor for ObjectInputStream were ever to
return, a new thread would be started to make that handshake available
to the input stream, but the input stream isn't going to return until it
gets that handshake.

In short, the solution is to be sure you've done everything you need to
do to have an active writer for a stream *before* you build an
ObjectInputStream from it. In your case, it means start the thread
before you wrap the streams.

I see what you're saying, but simply starting the thread sooner doesn't help
anything. The thread just waits for one byte of data and then returns one
byte. What exactly do you mean by "the data path to be complete"? This is my
first foray into the world of piped communication.
 
R

Ryan Stewart

Chris Smith said:
This isn't a problem with wrapping PipedInputStream. It's a problem
with when to create an ObjectInputStream. The constructor for
ObjectInputStream reads an initial handshake from its target stream
before continuing. (Similarly, ObjectOutputStream writes such a
handshake in its constructor.) If that initial handshake is not
available, it blocks until that handshake is available.

Since your sample code needs to start the second thread in order for the
data path to be complete, you are running into this problem.
ObjectOutputStream writes this handshake to its pipe, and it gets stored
in a buffer waiting for someone to read it. ObjectInputStream tries to
read the handshake from its stream, and blocks. Now you're
deadlocked... if the constructor for ObjectInputStream were ever to
return, a new thread would be started to make that handshake available
to the input stream, but the input stream isn't going to return until it
gets that handshake.

In short, the solution is to be sure you've done everything you need to
do to have an active writer for a stream *before* you build an
ObjectInputStream from it. In your case, it means start the thread
before you wrap the streams.

Okay, based on what you've said, I came up with something that works. Since
an ObjectOutputStream sends a header and an ObjectInputStream waits to
receive a header, you have to set them all up in the correct order, which is
complicated by the piped streams having to be connected before wrapping
them. If that's right, then there is a very limited number of ways to set it
up. Any comments on what I've done here?

// First class
import java.io.*;

public class TestOut {

public static void main(String[] args) {
try {
PipedOutputStream pipeOut = new PipedOutputStream();
PipedInputStream pipeIn = new PipedInputStream();
TestIn ti = new TestIn(pipeIn, pipeOut);
System.out.println("Wrapping...");
ObjectOutputStream oos = new ObjectOutputStream(pipeOut);
ti.start();
ObjectInputStream ois = new ObjectInputStream(pipeIn);
System.out.println("Done.");
pipeOut.write(5);
System.out.println("Waiting");
Thread.sleep(100);
int result = pipeIn.read();
System.out.println(result);
} catch (Exception e) {
e.printStackTrace();
}
}
}

// Second class
import java.io.*;

public class TestIn extends Thread {

PipedInputStream pipeIn;
PipedOutputStream pipeOut;
ObjectOutputStream oos;
ObjectInputStream ois;

public TestIn(PipedInputStream pipeIn, PipedOutputStream pipeOut) {
try {
this.pipeIn = new PipedInputStream(pipeOut);
this.pipeOut = new PipedOutputStream(pipeIn);
} catch (Exception e) {
e.printStackTrace();
}
}

public void run() {
try {
ois = new ObjectInputStream(this.pipeIn);
oos = new ObjectOutputStream(this.pipeOut);
System.out.println("Listening");
int data = pipeIn.read();
System.out.println("Received: " + data);
pipeOut.write(data * 5);
} catch (Exception e) {
e.printStackTrace();
}
}
}
 
S

Sudsy

Ryan Stewart wrote:
<snip>

Your code is still confusing streams! You're using pipeIn and pipeOut
instead of oos and ois. Here's some modified code which actually works
and uses the Object streams, with appropriate wrapping of the
primitives:

import java.io.*;

public class TestOut {
public static void main( String[] args ) {
try {
PipedInputStream pipeIn = new PipedInputStream();
PipedOutputStream pipeOut = new PipedOutputStream();
TestIn ti = new TestIn( pipeIn, pipeOut );
ti.start();
System.out.println( "Wrapping..." );
ObjectOutputStream oos = new ObjectOutputStream( pipeOut );
ObjectInputStream ois = new ObjectInputStream( pipeIn );
System.out.println( "Done wrapping." );
oos.writeObject( new Integer( 5 ) );
oos.flush();
Thread.sleep(100);
Integer result = (Integer) ois.readObject();
System.out.println( result.intValue() );
} catch( Exception e ) {
e.printStackTrace();
}
}
}

import java.io.*;

public class TestIn extends Thread {

PipedInputStream pipeIn;
PipedOutputStream pipeOut;
ObjectOutputStream oos;
ObjectInputStream ois;

public TestIn( PipedInputStream pipeIn, PipedOutputStream pipeOut ) {
try {
this.pipeOut = new PipedOutputStream( pipeIn );
this.pipeIn = new PipedInputStream( pipeOut );
} catch( Exception e ) {
e.printStackTrace();
}
}

public void run() {
try {
ois = new ObjectInputStream( pipeIn );
oos = new ObjectOutputStream( pipeOut );
System.out.println( "Listening" );
Integer data = (Integer) ois.readObject();
oos.writeObject( new Integer( data.intValue() * 5 ) );
oos.flush();
} catch( Exception e ) {
e.printStackTrace();
}
}
}

$ java TestOut
Wrapping...
Listening
Done wrapping.
25
$


Two notes:
- forgive the reformatting of code; I subscribe to the
"classic" K&R format
- you really shouldn't extend Thread but should implement
Runnable

See the archives for persuasive arguments on the latter point.
 
R

Ryan Stewart

Sudsy said:
Ryan Stewart wrote:
<snip>

Your code is still confusing streams! You're using pipeIn and pipeOut
instead of oos and ois. Here's some modified code which actually works
and uses the Object streams, with appropriate wrapping of the
primitives:

You missed the point. The problem wasn't using the object streams. It was
getting them created. I've got it figured out now, though. Thanks for the
reply.
 
R

Ryan Stewart

ak said:
May be we should ask you what do you want to achieve with PipedStreams?

____________

http://reader.imagero.com the best java image reader.

It's for a client-server type setup. I'm working on a Scrabble applet for
fun/learning. The idea is that there will be a server running and the client
will connect to it. That way there can be multiplayer games with people
logged in to the same server. That part is fine. But if the client can't
connect to a server for whatever reason, it will start an internal "server"
that simulates the functionality of a real server. When using a real server,
my client uses Object streams, so I'd like to set up the same streams to the
internal server so that after the connection process, whether it's connected
to a server or using the internal server, everything else happens the same:
send on the output stream, receive on the input stream. My internal server
runs in its own thread. Basically, it just waits for messages from the
client and replies to them appropriately.
 
C

Chris Smith

Ryan said:
I see what you're saying, but simply starting the thread sooner doesn't help
anything. The thread just waits for one byte of data and then returns one
byte.

Oops. Yes, I didn't pay enough attention to that part. I'm now
completely lost as to what you are trying to do. In any case, my
previous comments apply: make sure that the serialization handshake will
eventually occur *before* you create an ObjectInputStream.
What exactly do you mean by "the data path to be complete"? This is my
first foray into the world of piped communication.

I mean that you need for data to be able to pass all the way through
where it's going to pass. (I mistakenly thought you were using the
thread for something you aren't.) Since that doesn't apply, you simply
need to match ObjectOutputStream at one side with ObjectInputStream on
the other... and be sure that when you create the ObjectInputStream, you
don't need to to do anything else in the current thread before the
corresponding ObjectOutputStream is created.

Since my misunderstanding regarding your use of threads is cleared up, I
don't see that you're matching the ObjectInputStream and
ObjectOutputStream together at all, so you'll have to explain how you
want this to work before I can make specific recommendations.

--
www.designacourse.com
The Easiest Way to Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
 
R

Ryan Stewart

Chris Smith said:
Oops. Yes, I didn't pay enough attention to that part. I'm now
completely lost as to what you are trying to do. In any case, my
previous comments apply: make sure that the serialization handshake will
eventually occur *before* you create an ObjectInputStream.


I mean that you need for data to be able to pass all the way through
where it's going to pass. (I mistakenly thought you were using the
thread for something you aren't.) Since that doesn't apply, you simply
need to match ObjectOutputStream at one side with ObjectInputStream on
the other... and be sure that when you create the ObjectInputStream, you
don't need to to do anything else in the current thread before the
corresponding ObjectOutputStream is created.

Since my misunderstanding regarding your use of threads is cleared up, I
don't see that you're matching the ObjectInputStream and
ObjectOutputStream together at all, so you'll have to explain how you
want this to work before I can make specific recommendations.

I've figured out how they work together. See my other posts in this thread.
Part of my problem was that I was only trying to create an input and output
on the one side to start off with. (I intended to put the other side of them
in later, after I got these working.) I didn't realize at first that the
input and output streams have to be paired, but once you pointed out that
the ObjectInputStream blocks until it receives the handshake, it was just a
matter of time until I got it all working.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,743
Messages
2,569,478
Members
44,899
Latest member
RodneyMcAu

Latest Threads

Top