2017-08-03 89 views
4

我需要为交互式命令行程序编写包装程序。如何从另一个.NET程序使用交互式命令行程序

这意味着我需要能够通过其标准输入发送命令到其他程序,并通过其标准输出接收响应。

问题是,当输入流仍然打开时,标准输出流似乎被阻塞。只要我关闭输入流,我就会得到响应。但后来我无法发送更多命令。

这是我在用的那一刻(主要来自here):

void Main() { 
    Process process; 
    process = new Process(); 
    process.StartInfo.FileName = "atprogram.exe"; 
    process.StartInfo.Arguments = "interactive"; 

    // Set UseShellExecute to false for redirection. 
    process.StartInfo.UseShellExecute = false; 
    process.StartInfo.CreateNoWindow = true; 

    // Redirect the standard output of the command. 
    // This stream is read asynchronously using an event handler. 
    process.StartInfo.RedirectStandardOutput = true; 
    // Set our event handler to asynchronously read the output. 
    process.OutputDataReceived += (s, e) => Console.WriteLine(e.Data); 

    // Redirect standard input as well. This stream is used synchronously. 
    process.StartInfo.RedirectStandardInput = true; 
    process.Start(); 

    // Start the asynchronous read of the output stream. 
    process.BeginOutputReadLine(); 

    String inputText; 
    do 
    { 
     inputText = Console.ReadLine(); 
     if (inputText == "q") 
     { 
      process.StandardInput.Close(); // After this line the output stream unblocks 
      Console.ReadLine(); 
      return; 
     } 
     else if (!String.IsNullOrEmpty(inputText)) 
     { 
      process.StandardInput.WriteLine(inputText); 
     } 
    } 
} 

我也尝试同步读取标准输出流,但具有相同的结果。任何方法无限期调用输出流块,直到输入流被关闭 - 即使是Peek()EndOfStream

有什么办法以全双工方式与其他进程通信?

+0

你可以使异步线程? –

+0

@BenderBending是的,我可以,但这会有帮助吗? – Karsten

+0

我相信会的。 t一个线程上的输入流和另一个线程上的输出流。 –

回答

1

我试图用我自己的一个小测试套件重现您的问题。 而不是使用事件处理程序,我以最简单的方式做到这一点:同步。这样就不会增加额外的复杂性。

这里我的小“echoApp”我在写生锈,只是欢笑,也有机会运行到永恒的行终止战争的问题(\n VS \r VS \r\n)。根据您的命令行应用程序的编写方式,这确实可能是您的问题之一。

use std::io; 

fn main() { 
    let mut counter = 0; 
    loop { 
     let mut input = String::new(); 
     let _ = io::stdin().read_line(&mut input); 
     match &input.trim() as &str { 
      "quit" => break, 
      _ => { 
       println!("{}: {}", counter, input); 
       counter += 1; 
      } 
     } 
    } 
} 

而且 - 是一个懒惰的骨头谁不喜欢创造这样一个小的测试解决方案,我用来代替C#进行操纵侧F# - 这是很容易阅读,我认为:

open System.Diagnostics; 

let echoPath = @"E:\R\rustic\echo\echoApp\target\debug\echoApp.exe" 

let createControlledProcess path = 
    let p = new Process() 
    p.StartInfo.UseShellExecute <- false 
    p.StartInfo.RedirectStandardInput <- true 
    p.StartInfo.RedirectStandardOutput <- true 
    p.StartInfo.Arguments <- "" 
    p.StartInfo.FileName <- path 
    p.StartInfo.CreateNoWindow <- true 
    p 

let startupControlledProcess (p : Process) = 
    if p.Start() 
    then 
     p.StandardInput.NewLine <- "\r\n" 
    else() 

let shutdownControlledProcess (p : Process) = 
    p.StandardInput.WriteLine("quit"); 
    p.WaitForExit() 
    p.Close() 

let interact (p : Process) (arg : string) : string = 
    p.StandardInput.WriteLine(arg); 
    let o = p.StandardOutput.ReadLine() 
    // we get funny empty lines every other time... 
    // probably some line termination problem (unix \n vs \r\n etc - 
    // who can tell what rust std::io does...?) 
    if o = "" then p.StandardOutput.ReadLine() 
    else o 

let p = createControlledProcess echoPath 
startupControlledProcess p 
let results = 
    [ 
     interact p "Hello" 
     interact p "World" 
     interact p "Whatever" 
     interact p "floats" 
     interact p "your" 
     interact p "boat" 
    ] 
shutdownControlledProcess p 

在F#互动(CTRL-A在Visual Studio中ALT-回车)收率执行此:

VAL echoPath:字符串=“E:\ r \质朴\回波\ echoApp \目标\调试\ echoApp。 exe“

VAL createControlledProcess:路径:串 - >过程

VAL startupControlledProcess:P:过程 - >单元

VAL shutdownControlledProcess:P:过程 - >单元

VAL相互作用:P:过程 - >精氨酸:string - > string

val p:Process = System.Diagnostics。处理

val结果:string list =

[“0:Hello”; “1:世界”; “2:无论”; “3:浮动”; “4:你的”; “5:船”]

VAL是:单位=()

我无法重现的任何阻塞或死锁等 所以,你的情况我会尝试以调查是否也许你NewLine性能需求一些调整(见功能startupControlledProcess。如果受控程序不能识别输入为一行,它可能不会响应,仍然等待输入行的其余部分,你可能会得到你有的效果。

+0

谢谢您的广泛答复!我尝试了不同的'NewLine'值,但没有成功。我也尝试从python开始这个过程,得到相似的结果。我认为这与其他应用程序的编写方式有关。我有一个与WinSCP类似的问题,直到我发现它有一个单独的WinSCP.com文件,它在命令行上运行得更好。我仍然不知道这两者之间有什么区别,并且据我所知,除了程序没有其他选择... – Karsten

+0

也许您需要尝试如果目标程序依赖于特定的工作目录。一些(写得不好的)程序会这样做。这可能会阻止程序正常工作。或者也许它依赖于一些环境设置,因为来自unix世界的许多程序都这样做。您可以在启动应用程序时指定工作目录和环境设置(可能是PATH?)。 – BitTickler

相关问题