tags:

views:

432

answers:

1

I am using Java Process API to write a class that receives binary input from the network (say via TCP port A), processes it and writes binary output to the network (say via TCP port B). I am using Windows XP. The code looks like this. There are two functions called run() and receive(): run is called once at the start, while receive is called whenever there is a new input received via the network. Run and receive are called from different threads.

The run process starts an exe and receives the input and output stream of the exe. Run also starts a new thread to write output from the exe on to the port B.

    public void run() {
        try {
            Process prc = // some exe is `start`ed using ProcessBuilder
                    OutputStream procStdIn = new BufferedOutputStream(prc.getOutputStream());
            InputStream procStdOut = new BufferedInputStream(prc.getInputStream());
                    Thread t = new Thread(new ProcStdOutputToPort(procStdOut));
                    t.start();

                    prc.waitFor();
                    t.join();
                    procStdIn.close();
                    procStdOut.close();
        } catch (Exception e) {
            e.printStackTrace();
            printError("Error : " + e.getMessage());
        }
    }

The receive forwards the received input from the port A to the exe.

    public void receive(byte[] b) throws Exception {
        procStdIn.write(b);
    }

    class ProcStdOutputToPort implements Runnable {
        private BufferedInputStream bis;
        public ProcStdOutputToPort(BufferedInputStream bis) {
            this.bis = bis;
        }
        public void run() {
            try {
                int bytesRead;
                int bufLen = 1024;
                byte[] buffer = new byte[bufLen];
                while ((bytesRead = bis.read(buffer)) != -1) {
                    // write output to the network
                }
            } catch (IOException ex) {
                Logger.getLogger().log(Level.SEVERE, null, ex);
            }
        }
    }

The problem is that I am getting the following stack inside receive() and the prc.waitfor() returns immediately afterwards. The line number shows that the stack is while writing to the exe.

 The pipe has been ended
 java.io.IOException: The pipe has been ended
 at java.io.FileOutputStream.writeBytes(Native Method)
 at java.io.FileOutputStream.write(FileOutputStream.java:260)
 at java.io.BufferedOutputStream.write(BufferedOutputStream.java:105)
 at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:65)
 at java.io.BufferedOutputStream.write(BufferedOutputStream.java:109)
 at java.io.FilterOutputStream.write(FilterOutputStream.java:80)
 at xxx.receive(xxx.java:86)

Any advice about this will be appreciated.

+1  A: 

This means you are writing to the pipe after the other end has already closed it.

That indicates a major error in your application protocol.

EJP
The closed pipe is the one used to write to the exe process. So the protocol in question is the Java Process API.
Amit Kumar
The Java Process API doesn't *have* a protocol. The 'other end [that] has already closed it' is the process you exec'd. So you are writing something to the process after it has stopped reading. So the protocol in question is the protocol between your application and the process you are executing
EJP
This is strange, as I have tested the other process outside java using command prompt and it works well there. Seems there is some bug in the java code. Thanks for your comments.
Amit Kumar
And what happened when you tried to write to the other process after it had closed its input? How did you test that. DID you test that?You need to understand this point. Writing to a pipe or socket that has already been closed by the peer will always produce an error condition and it is always wrong.
EJP
Yes, I understand it is an error to write to a pipe closed by the peer. No, I didn't test the scenario you described. But this is something that should not happen: The exec'd process should not stop reading in the middle. On the command line it does not stop reading in the middle, so I do not understand why it stops reading in the middle when exec'd.
Amit Kumar
The exec'd process hasn't just 'stopped reading in the middle'. It has closed the connection. Most likely it has exited. You need to detect that case and stop writing to it.
EJP