Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating named pipes in Java

I am experimenting with creating named pipes using Java. I am using Linux. However, I am running into a problem where writing to the pipe hangs.

    File fifo = fifoCreator.createFifoPipe("fifo");
    String[] command = new String[] {"cat", fifo.getAbsolutePath()};
    process = Runtime.getRuntime().exec(command);

    FileWriter fw = new FileWriter(fifo.getAbsoluteFile());
    BufferedWriter bw = new BufferedWriter(fw);
    bw.write(boxString); //hangs here
    bw.close();
    process.waitFor();
    fifoCreator.removeFifoPipe(fifo.toString());

fifoCreator:

@Override
public File createFifoPipe(String fifoName) throws IOException, InterruptedException {
    Path fifoPath = propertiesManager.getTmpFilePath(fifoName);
    Process process = null;
    String[] command = new String[] {"mkfifo", fifoPath.toString()};
    process = Runtime.getRuntime().exec(command);
    process.waitFor();
    return new File(fifoPath.toString());
}

@Override
public File getFifoPipe(String fifoName) {
    Path fifoPath = propertiesManager.getTmpFilePath(fifoName);
    return new File(fifoPath.toString());
}

@Override
public void removeFifoPipe(String fifoName) throws IOException {
    Files.delete(propertiesManager.getTmpFilePath(fifoName));
}

I am writing a string that consists of 1000 lines. Writing 100 lines work but 1000 lines doesn't.

However, if I run "cat fifo" on an external shell, then the program proceeds and writes everything out without hanging. Its strange how the cat subprocess launched by this program doesn't work.

EDIT: I did a ps on the subprocess and it has the status "S".

like image 444
mrQWERTY Avatar asked Feb 09 '23 17:02

mrQWERTY


1 Answers

External processes have input and output that you need to handle. Otherwise, they may hang, though the exact point at which they hang varies.

The easiest way to solve your issue is to change every occurrence of this:

process = Runtime.getRuntime().exec(command);

to this:

process = new ProcessBuilder(command).inheritIO().start();

Runtime.exec is obsolete. Use ProcessBuilder instead.

UPDATE:

inheritIO() is shorthand for redirecting all of the Process's input and output to those of the parent Java process. You can instead redirect only the input, and read the output yourself:

process = new ProcessBuilder(command).redirectInput(
    ProcessBuilder.Redirect.INHERIT).start();

Then you will need to read the process's output from process.getInputStream().

like image 61
VGR Avatar answered Feb 12 '23 06:02

VGR