【问题标题】:Writing Standard Input and waiting for Standard Output写入标准输入并等待标准输出
【发布时间】:2009-10-28 16:15:36
【问题描述】:

我正在尝试创建一个保持 netsh windows 命令行工具打开的线程,这样我就可以执行 netsh 命令而无需每次都打开它。

问题是,一旦我创建了线程,只有第一个命令调用有效……随后的调用似乎没有效果。

这是我的代码:

public class NetshThread implements Runnable{
 private static Process netshProcess = null;
 private static BufferedInputStream netshInStream = null;
 private static BufferedOutputStream netshOutStream = null;
 public BufferedReader inPipe = null;

 public void run(){
  startNetsh();
 }

 public void startNetsh(){
  try {
   netshProcess = Runtime.getRuntime().exec("netsh");
   netshInStream = new BufferedInputStream(netshProcess.getInputStream());
   netshOutStream =  new BufferedOutputStream(netshProcess.getOutputStream());
   inPipe = new BufferedReader(new InputStreamReader(netshInStream));
  } catch (IOException e) {
   e.printStackTrace();
  }
 } 

 public void executeCommand(String command){
  System.out.println("Executing: " + command);
  try {
   String str = "";
   netshOutStream.write(command.getBytes());
   netshOutStream.close();
   while ((str = inPipe.readLine()) != null) {
                System.out.println(str);
            }
  } catch (IOException e) {
   e.printStackTrace();
  }
 }
 public void closeNetsh(){
  executeCommand("exit");
 }

 public static void main(String[] args){
  NetshThread nthread = new NetshThread();
  nthread.run();
  String command = "int ip set address " +
    "\"Local Area Connection 6\" static .69.69.69 255.255.255.0";
  nthread.executeCommand(command);
  command = "int ip set address " +
    "\"Local Area Connection 6\" static 69.69.69.69 255.255.255.0";
  nthread.executeCommand(command);
  System.out.println("*** DONE ***");
 }
}

谢谢!!! =)

更新 1:

好的...我现在使用的是 PrintWriter...所以我想我不需要再刷新任何东西了,因为构造函数是:

new PrintWriter(netshOutStream, true); (就像闪亮先生告诉我的那样)......

假设我决定在第一个输出行可用时中断 while 循环...我也不工作...下一个命令不会执行...我的代码现在看起来像:

import java.io.*;

public class NetshThread implements Runnable{
    private static Process netshProcess = null;
    private static BufferedInputStream netshInStream = null;
    private static BufferedOutputStream netshOutStream = null;
    public BufferedReader inPipe = null;
    private PrintWriter netshWriter = null;

    public void run(){
        startNetsh();       
    }

    public void startNetsh(){
        try {
            netshProcess = Runtime.getRuntime().exec("netsh");
            netshInStream = new BufferedInputStream(netshProcess.getInputStream());
            netshOutStream =  new BufferedOutputStream(netshProcess.getOutputStream());
            netshWriter = new PrintWriter(netshOutStream, true);
            inPipe = new BufferedReader(new InputStreamReader(netshInStream));
        } catch (IOException e) {
            e.printStackTrace();
        }
    } 

    public void executeCommand(String command){
        System.out.println("Executing: " + command);
        try {
            String str = "";
            netshWriter.println(command);
            while ((str = inPipe.readLine()) != null) {
                System.out.println(str);
                break;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public void closeNetsh(){
        executeCommand("exit");
    }

    public static void main(String[] args){     
        NetshThread nthread = new NetshThread();
        Thread xs = new Thread(nthread);
        xs.run();
        String command = "int ip set address " +
                "\"Local Area Connection 6\" static .69.69.69 255.255.255.0";
        nthread.executeCommand(command);
        command = "int ip set address " +
                "\"Local Area Connection 6\" static 69.69.69.69 255.255.255.0";
        nthread.executeCommand(command);
        System.out.println("*** DONE ***");
    }
}

我得到的输出:

执行:int ip set address "Local 区域连接 6" 静态 .69.69.69 255.255.255.0 netsh>.69.69.69 不是 addr 可接受的值。 执行:int ip set address "Local 区域连接 6" 静态 69.69.69.69

为什么第二条命令没有执行???

255.255.255.0

* 完成 *

更新 2:

在一位老师在西班牙 Windows 环境中试用我的应用程序之前,一切似乎都很好......

我的代码如下所示:

扫描仪 fi = new Scanner(netshProcess.getInputStream());

public void executeCommand(String command) {
        System.out.println("Executing: " + command);
        String str = "";
        netshWriter.println(command);
        fi.skip("\\s*");
        str = fi.nextLine();
        System.out.println(str);
}

我需要以某种方式将 netshWriter 编码设置为 windows 默认值。

谁能知道谁来做这个?

【问题讨论】:

  • 我相信这是因为 readLine() 正在阻塞等待来自命令的更多输入。看我之前的回答
  • 您不想实际创建一个 java 线程 - 这可能会导致问题(在 startNetsh 完成之前调用 executeCommand)。在发送下一个命令之前,您需要阅读 netsh 的所有(并且仅是所有)输出。如果您只读取一行,并且它试图向您写入多行,那么它可能正在等待 write() 调用并且不会接收您的下一个命令。

标签: java process input standards


【解决方案1】:

您正在关闭输出流。

【讨论】:

    【解决方案2】:

    您需要将流处理移动到单独的线程中。发生的事情是 inPipe.readLine() 正在阻塞等待 netsh 返回数据。 Apache 有一个处理进程处理的包。我会考虑使用它而不是自己滚动 (http://commons.apache.org/exec/)

    【讨论】:

      【解决方案3】:

      这在很多方面似乎都是错误的。

      首先,为什么是 Runnable 对象?这永远不会传递给任何地方的线程。您创建的唯一线程不是 java 线程,而是由 exec() 创建的 OS 进程。

      其次,您需要一种知道 netsh 何时完成的方法。您读取 netsh 输出的循环将永远运行,因为 readLine 只会在 netsh 关闭其标准输出时返回 null (在您的情况下永远不会)。您需要查找 netsh 在处理完您的请求后打印的一些标准内容。

      正如其他人所提到的,关闭是不好的。使用冲洗。并希望 netsh 使用冲洗回给你...

      【讨论】:

        【解决方案4】:

        我会尝试:

        PrintWriter netshWriter = new PrintWriter(netshOutputStream, true); // auto-flush writer
        
        netshWriter.println(command);
        

        不关闭()流,自动刷新流,并使用写入器发送字符数据,而不是依赖于平台“本机字符集”。

        【讨论】:

        • 嗨!!!...我尝试了你的解决方案,同样的事情......它卡住了:while ((str = inPipe.readLine()) != null) { System.out .println(str); }
        【解决方案5】:

        您确实需要删除close,否则您将永远无法执行另一个命令。当你说一旦 close() 调用被移除后“它不会工作”,你的意思是 no 命令被处理了吗?

        很有可能,在您发送命令的字节后,您需要发送某种确认密钥以启动进程,嗯,处理它。如果您通常从键盘输入它,它可能就像回车一样简单,否则它可能需要是 Ctrl-D 或类似的。

        我会尝试将 close() 行替换为

        netshOutStream.write('\n');
        

        看看这是否有效。根据软件的不同,您可能需要更改发送来表示命令结束的字符,但这种通用方法应该可以帮助您完成。

        编辑:

        打电话也是谨慎的做法

        netshOutStream.flush();
        

        在上述几行之后;如果没有刷新,则无法保证您的数据会被写入,事实上,由于您使用的是 BufferedInputStream,我 99% 确信在刷新流之前不会写入任何内容。因此,为什么代码随后会阻塞,因为您正在等待响应,而进程还没有看到任何输入,并且正在等待 发送一些信息。

        【讨论】:

        • 谢谢! buuuut ...我用 .write('\n') 替换了 .close 行,而位于 .write('\n') 之后的 while 循环似乎永远卡住了 =S....
        • 在删除 close() 调用后,它执行第一个命令,它向我显示它的输出,但它永远不会离开 while 循环,仅此而已,而不是它执行的其他东西。
        • 我刚刚将我的代码更改为: PrintWriter netshWriter = new PrintWriter(netshOutputStream, true); // 自动刷新写入器 netshWriter.println(command);所以我不必担心刷新流......它执行第一个命令,向我显示一些输出并在while循环中被阻塞,然后,没有其他事情发生=S
        【解决方案6】:

        我使用扫描仪而不是 BufferedReader,只是因为我喜欢它。所以这段代码有效:

        Scanner fi = new Scanner(netshProcess.getInputStream());
        
        
        public void executeCommand(String command) {
            System.out.println("Executing: " + command);
            String str = "";
            netshWriter.println(command);
            fi.skip("\\s*");
            str = fi.nextLine();
            System.out.println(str);
        }
        

        它执行两个命令。

        【讨论】:

        • THAAAAAAAAAAAAAAAAAAAAAANK YOUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! =) 我爱你!
        • 我已经习惯了这里的大多数用户都是男性的事实,所以在我读到你的名字之前最后一句话有点令人震惊:) 祝你好运,瓦伦蒂娜。顺便说一句,你是俄罗斯人吗?