尝试执行多个命令时出错
Getting an error when attempting to execute multiple commands
该项目出于各种目的对命令行进行了许多不同的调用。为了使这更容易,我写了一个方法,只需要一个人输入命令作为参数:
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;
}
}
}
}
}
我异步调用它的原因是我调用的一些命令不能保证运行工作,所以理想情况下,如果超时我可以重试。
当 运行 运行我的程序时,我注意到一个命令 "time /t" 总是会超时。
为了进行调查,我尝试 运行 在我的程序的主循环中独立地合并代码,令人惊讶的是 运行。
我很好奇为什么这个完全相同的命令在一个地方执行而在另一个地方却没有 运行。我 运行 另一个测试,我将命令调用置于 while 循环中,很快发现命令调用在恰好 4 次 AsyncCommandCall 方法调用后按预期停止工作。回顾我的代码,在我调用 "time /t" 之前正好有 4 个命令调用。我想知道这是 api 中的错误还是我做错了什么
在有人建议之前,我还应该注意,我确实编写了一个不包含 "using" 语句的同步命令调用方法,但是 运行ning 它会导致挂起 "process.WaitForExit()".任何帮助将不胜感激。
编辑
我在测试期间注意到,如果我增加作为参数传递的超时时间,则会成功调用更多迭代。是否有某种可以清除的缓冲区,以便处理时间不会随着每次调用而增加?
事实证明,此问题取决于该方法添加到每个命令调用的 /k
参数。 /k
标志告诉控制台保持输出打开,导致使用这种异步方法的一致超时、阻塞系统内存和阻止 process.WaitForExit()
返回。相反,我现在在每个命令调用之前使用 /c
标志,并成功读取每个命令的输出。在连续调用 AsyncCommandCall(command, null, 100)
1000 次并循环执行三个命令(一个 echo
、一个 dir
和一个 psexec
)时,有 0 次超时和 0 次读取失败。
该项目出于各种目的对命令行进行了许多不同的调用。为了使这更容易,我写了一个方法,只需要一个人输入命令作为参数:
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;
}
}
}
}
}
我异步调用它的原因是我调用的一些命令不能保证运行工作,所以理想情况下,如果超时我可以重试。
当 运行 运行我的程序时,我注意到一个命令 "time /t" 总是会超时。 为了进行调查,我尝试 运行 在我的程序的主循环中独立地合并代码,令人惊讶的是 运行。
我很好奇为什么这个完全相同的命令在一个地方执行而在另一个地方却没有 运行。我 运行 另一个测试,我将命令调用置于 while 循环中,很快发现命令调用在恰好 4 次 AsyncCommandCall 方法调用后按预期停止工作。回顾我的代码,在我调用 "time /t" 之前正好有 4 个命令调用。我想知道这是 api 中的错误还是我做错了什么
在有人建议之前,我还应该注意,我确实编写了一个不包含 "using" 语句的同步命令调用方法,但是 运行ning 它会导致挂起 "process.WaitForExit()".任何帮助将不胜感激。
编辑
我在测试期间注意到,如果我增加作为参数传递的超时时间,则会成功调用更多迭代。是否有某种可以清除的缓冲区,以便处理时间不会随着每次调用而增加?
事实证明,此问题取决于该方法添加到每个命令调用的 /k
参数。 /k
标志告诉控制台保持输出打开,导致使用这种异步方法的一致超时、阻塞系统内存和阻止 process.WaitForExit()
返回。相反,我现在在每个命令调用之前使用 /c
标志,并成功读取每个命令的输出。在连续调用 AsyncCommandCall(command, null, 100)
1000 次并循环执行三个命令(一个 echo
、一个 dir
和一个 psexec
)时,有 0 次超时和 0 次读取失败。