简体   繁体   English

使用 ProcessBuilder 发送多个命令?

[英]Send multiples commands with ProcessBuilder?

I want to spawn a child process in Java and send different commands inside the app.我想在 Java 中生成一个子进程并在应用程序内发送不同的命令。 My child process has authentication and each user can have a variety of internal commands.我的子进程具有身份验证,每个用户都可以拥有各种内部命令。

For example:例如:

> login myuser passowrd
OK
> list certs
cert1 abc
cert2 efg
> logout
> exit

Well, to simulate that I will make my example with "node" as IO CLI.好吧,为了模拟,我将使用“node”作为 IO CLI 来制作我的示例。

public class JAVAMain {

    public static void main(String[] args) throws Exception {
        action();
    }

    public static String action() throws Exception {
        ProcessBuilder pb = new ProcessBuilder("node");
        pb.redirectErrorStream(true);
        Process process = pb.start();

        // streams
        InputStream stdout = process.getInputStream();
        OutputStream stdin = process.getOutputStream();
        BufferedReader reader = new BufferedReader(new InputStreamReader(stdout));
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(stdin));
        String buff = "";
        String res = "";

        System.out.println("1");
        writer.write("console.log('OK');\n"); // simulate "login answer"
        writer.flush();

        System.out.println("2");
        res = "";
        while ((buff = reader.readLine()) != null) {
            res += buff;
        }

        if (!res.equals("OK")) {
            reader.close();
            writer.close();
            throw new Exception("Invalid auth");
        }

        System.out.println("3");
        writer.write("console.log('any text...');\n");
        writer.flush();

        System.out.println("4");
        res = "";
        while ((buff = reader.readLine()) != null) {
            res += buff;
        }

        reader.close();
        writer.close();
        return res;
    }
}

I expect to print 1,2,3,4 and get the res any text... for this example.我希望打印1,2,3,4并获取 res any text...对于这个例子。 But the program never stops and stay in 1,2 .但是程序永远不会停止并停留在1,2中。 If I close the writer after the flush in 1 I get this output:如果我在1刷新后关闭编写writer ,我会得到这个 output:

1
2
3
Exception in thread "main" java.io.IOException: Stream closed
        at java.io.BufferedWriter.ensureOpen(BufferedWriter.java:116)
        at java.io.BufferedWriter.write(BufferedWriter.java:221)
        at java.io.Writer.write(Writer.java:157)
        at com.keynua.kades.JAVAMain2.action(JAVAMain2.java:48)
        at com.keynua.kades.JAVAMain2.main(JAVAMain2.java:14)

That's why I close the writer and the reader works but I can't write again.这就是为什么我关闭writerreader工作,但我不能再写。 So, how I can make to send multiples commands to the child app and read the output to follow the flow with other commands?那么,我如何才能向子应用程序发送多个命令并阅读 output 以跟随其他命令的流程?

One problem is that your while loops一个问题是你的 while 循环

while ((buff = reader.readLine()) != null) { ... }

only terminate when the reader has reached the end of the input stream.仅当reader到达输入 stream 的末尾时才终止。

The end of the input stream is only reached when the subprocess terminates.输入 stream 仅在子进程终止时到达末尾。


The second problem is that you seem to be using NodeJS as sample command executor.第二个问题是您似乎使用 NodeJS 作为示例命令执行器。

  • If NodeJS is started from a console, you can enter JavaScript statements and they are executed one by one.如果 NodeJS 是从控制台启动的,可以输入 JavaScript 语句,然后一一执行。
  • You are however starting NodeJS not from a console, but from some other application.但是,您不是从控制台启动 NodeJS,而是从其他一些应用程序启动。 In this case, NodeJS wants to read a complete script from stdin and executes the complete script at once在这种情况下,NodeJS 想要从标准输入读取完整的脚本并立即执行完整的脚本
  • You could start NodeJS with the -i parameter (force interactive mode), at the expense of some additional output.您可以使用-i参数(强制交互模式)启动 NodeJS,但会牺牲一些额外的 output。

To achieve this, you would create the ProcessBuilder with为此,您将创建ProcessBuilder

ProcessBuilder pb = new ProcessBuilder("node", "-i");

Communicating with a subprocess in this way only works when you know how many lines to read from the reader before sending the next command.仅当您知道在发送下一个命令之前要从reader读取多少行时,以这种方式与子进程通信才有效。

Knowing how many lines to read can mean:知道要阅读多少行可能意味着:

  • knowing how many lines of output a command produces (login: 1 line of output, logout: no output)知道命令产生多少行 output (登录:1 行 output,注销:无输出)
  • knowing that a command produces a distinct last line (for example an empty line or a line with only "END" in it)知道命令会产生不同的最后一行(例如空行或仅包含“END”的行)
  • that a command produces a line count as the first result一个命令产生一个行数作为第一个结果
  • executing another command first that returns the result line count of the subsequent command首先执行另一个命令,返回后续命令的结果行数

The list certs command could either: list certs命令可以:

  • produce生产

     cert1 abc cert2 def END
  • produce (where the last line would be empty instead of containing a dot)产生(最后一行是空的而不是包含一个点)

     cert1 abc cert2 def.
  • produce生产

     2 certs cert1 abc cert2 def
  • or you could execute a count certs command before executing list certs或者您可以在执行list certs之前执行count certs命令

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM