Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/265.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 尝试执行多个命令时出错_C#_Console Application_Command Prompt - Fatal编程技术网

C# 尝试执行多个命令时出错

C# 尝试执行多个命令时出错,c#,console-application,command-prompt,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;

项目出于各种目的对命令行进行许多不同的调用。为了简化这一过程,我编写了一个方法,它只需要一个人在中输入命令作为参数:

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;
                }
            }
        }
    }

}
公共字符串AsyncCommandCall(字符串sCommand、列表lOutput、int超时)
{
如果(!sCommand.ToLower().Substring(0,5).包含(“/k”))
sCommand=“/k”+sCommand;
使用(流程=新流程())
{
ProcessStartInfo startInfo=新的ProcessStartInfo();
startInfo.FileName=“cmd.exe”;
startInfo.RedirectStandardOutput=true;
startInfo.RedirectStandardError=true;
startInfo.UseShellExecute=false;
startInfo.Arguments=sCommand;
startInfo.CreateNoWindow=true;
process.StartInfo=StartInfo;
列表输出=新列表();
列表错误=新建列表();
使用(AutoResetEvent outputWaitHandle=new AutoResetEvent(false))
使用(AutoResetEvent errorWaitHandle=new AutoResetEvent(false))
{
process.OutputDataReceived+=(发送方,e)=>
{
如果(例如,数据==null)
{
outputWaitHandle.Set();
}
其他的
{
如果(!String.IsNullOrEmpty(e.Data))
输出。添加(如数据);
}
};
process.ErrorDataReceived+=(发送方,e)=>
{
如果(例如,数据==null)
{
errorWaitHandle.Set();
}
其他的
{
输出。添加(如数据);
}
};
process.Start();
process.BeginErrorReadLine();
process.BeginOutputReadLine();
if(process.WaitForExit(超时)&&outputWaitHandle.WaitOne(超时)&&errorWaitHandle.WaitOne(超时))
{
m_sCmdOutput.Clear();
m_sCmdError.Clear();
m_sCmdOutput.AddRange(输出);
m_sCmdError.AddRange(错误);
如果(lOutput!=null)
{
lOutput.AddRange(输出);
}
返回聚合列表(输出);
}
其他的
{
process.Close();
//暂停不一定意味着事情没有发生,很可能它没有处理。
如果(error.Count>0)
{
m_sCmdError.Clear();
m_sCmdError.AddRange(错误);
}
调试(“+sCommand”的线程超时);
如果(output.Count>0)
{
m_sCmdOutput.Clear();
m_sCmdOutput.AddRange(输出);
如果(lOutput!=null)
{
lOutput.AddRange(输出);
}
返回(聚合列表(输出));
}
其他的
{
调试(“返回空”);
返回null;
}
}
}
}
}
我异步调用它的原因是,我调用的一些命令不能保证工作,因此理想情况下,如果超时,这将允许我重试

在运行我的程序时,我注意到一个命令“time/t”总是超时。 为了进行调查,我尝试在程序的主循环中独立运行代码,但令人惊讶的是,它居然运行了

我开始好奇,为什么这个完全相同的命令在一个地方执行,而在另一个地方却无法运行。我运行了另一个测试,将命令调用放在while循环中,很快发现命令调用在恰好4次AsyncCommandCall方法调用后停止工作。回顾我的代码,在我调用“time/t”之前,总共有4次命令调用。我想知道这是api中的一个bug还是我做错了什么

在任何人提出建议之前,我还应该注意,我确实编写了一个同步命令调用方法,该方法不包含“using”语句,但运行它会导致挂起“process.WaitForExit()”。任何帮助都将不胜感激

编辑


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

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

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