尝试执行多个命令时出错

时间:2015-07-22 22:49:18

标签: c# console-application command-prompt

为了各种目的,项目对命令行进行了许多不同的调用。为了使这更容易,我写了一个方法,只需要一个人作为参数输入命令:

public string AsyncCommandCall(string sCommand, List<string> lOutput, int timeout)
{
    if (!sCommand.ToLower().Substring(0, 5).Contains("/k"))
        sCommand = "/k " + sCommand;
    using(Process process = new Process())
    {
        ProcessStartInfo startInfo = new ProcessStartInfo();
        startInfo.FileName = "cmd.exe";

        startInfo.RedirectStandardOutput = true;
        startInfo.RedirectStandardError = true;
        startInfo.UseShellExecute = false;
        startInfo.Arguments = sCommand;
        startInfo.CreateNoWindow = true;

        process.StartInfo = startInfo;

        List<string> output = new List<string>();
        List<string> error = new List<string>();
        using(AutoResetEvent outputWaitHandle = new AutoResetEvent(false))
        using(AutoResetEvent errorWaitHandle = new AutoResetEvent(false))
        {
            process.OutputDataReceived += (sender, e) =>
            {
                if (e.Data == null)
                {
                    outputWaitHandle.Set();
                }
                else
                {
                    if(!String.IsNullOrEmpty(e.Data))
                        output.Add(e.Data);
                }
            };
            process.ErrorDataReceived += (sender, e) =>
            {
                if(e.Data == null)
                {
                    errorWaitHandle.Set();
                }
                else
                {
                    output.Add(e.Data);
                }
            };

            process.Start();

            process.BeginErrorReadLine();
            process.BeginOutputReadLine();

            if(process.WaitForExit(timeout) && outputWaitHandle.WaitOne(timeout) && errorWaitHandle.WaitOne(timeout))
            {
                m_sCmdOutput.Clear();
                m_sCmdError.Clear();
                m_sCmdOutput.AddRange(output);
                m_sCmdError.AddRange(error);
                if(lOutput != null)
                {
                    lOutput.AddRange(output);
                }
                return AggregateList(output);
            }
            else
            {
                process.Close();

                //a time out doens't necessarily mean that stuff didn't happen, it's likely that it didn't process.

                if(error.Count > 0)
                {
                    m_sCmdError.Clear();
                    m_sCmdError.AddRange(error);
                }
                Debug("Thread time out for " + sCommand);
                if (output.Count > 0)
                {
                    m_sCmdOutput.Clear();
                    m_sCmdOutput.AddRange(output);
                    if (lOutput != null)
                    {
                        lOutput.AddRange(output);
                    }
                    return (AggregateList(output));
                }
                else
                {
                    Debug("Returning null");
                    return null;
                }
            }
        }
    }

}

我异步调用它的原因是我调用的一些命令不能保证工作,所以理想情况下,如果它超时,我会再次尝试。

运行我的程序时,我注意到一个命令,&#34; time / t&#34;永远都会超时。 为了调查,我尝试在我的程序的主循环中独立运行代码,并且令人惊讶的是它运行了。

我很好奇为什么这个完全相同的命令在一次执行而无法在另一个地方运行。我运行了另一个测试,我将命令调用放入while循环,很快发现命令调用在4个AsyncCommandCall方法调用之后停止按预期工作。回顾一下我的代码,在我调用&#34; time / t&#34;之前,正好有4个命令调用。我想知道这是api中的错误还是我做错了什么

在有人提出建议之前,我还应该注意到我写了一个同步命令调用方法,该方法不包含&#34;使用&#34;声明,但运行它导致挂起&#34; process.WaitForExit()&#34;。任何帮助将不胜感激。

修改

我在测试期间注意到,如果我增加作为参数传递的超时,则会成功调用更多迭代。是否有某种缓冲区可以清除,以便每次调用都不会增加处理时间?

1 个答案:

答案 0 :(得分:0)

事实证明,此问题取决于方法添加到每个命令调用的/k参数。 /k标志告诉控制台保持输出打开,导致使用此异步方法的一致超时,阻塞系统内存以及阻止process.WaitForExit()返回。相反,我现在在每次命令调用之前使用/c标志,并成功读取每个命令的输出。在通过三个命令(An AsyncCommandCall(command, null, 100)echodir)循环调用psexec 1000次时,有0个超时和0个读取失败。< / p>