过去几天,我正在尝试使以下代码同步工作:
Process process = new Process();
process.StartInfo.FileName = @"c:\plink.exe";
process.StartInfo.Arguments = "-t -ssh -l username -pw password 1.1.1.1";
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardInput = true;
process.Start();
StreamWriter sw = process.StandardOutput;
StreamReader sr = process.StandardInput;
string output="";
sw.WriteLine ("configure terminal");
sw.Flush();
while (sr.Peek() > -1)
{
output += (char) sr.Read();
}
if (output.Contains("(config)")
{
output="";
sw.WriteLine ("interface TenGig1/0/1");
sw.Flush();
while (!sr.EndOfStream)
{
output+= (char) sr.Read();
}
if (output.Contains("(config-if"))
{
sw.WriteLine ("shutdown");
sw.Flush();
}
}
问题 - 读取挂起!
VisualStudio / IIS 8无处不在。每个Read操作都易受影响,更常见的是上面的代码中的每个Read都挂起,而是成功读取。请注意,在同一个项目中,我有很多异步重定向,它们像魅力一样工作。然而,在这里,我被迫同步 - 因为我阅读并以交互方式回应我的红色。任何建议都会受到欢迎。
编辑1 删除我在寻求社区帮助之前所采取的调试步骤。 澄清第一次和第二次测试的测试条件不同,因为流似乎在EndOfStream处的其他方式。
答案 0 :(得分:0)
我有一个IIS-Application,几乎完全相同。我的代码是:
var a_proc = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = @"C:\Test.exe",
Arguments = $"-path {a_file}",
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true
}
};
a_proc.Start();
while (!a_proc.StandardOutput.EndOfStream)
{
string line = a_proc.StandardOutput.ReadLine().Trim();
a_result += line + '\n';
}
此代码将启动exe并读取任何控制台输出,直到控制台应用程序关闭。它读取同步,这意味着它将在此行string line = a_proc.StandardOutput.ReadLine().Trim();
等待,直到控制台写入新行。这可以被视为“挂起”,但实际上它只是等待读取新行。
我猜问题就在你的行while (!sr.EndOfStream)
,代码等待控制台关闭。但是我认为你想在此之后编写/“关闭”控制台。这对我来说毫无意义。尝试使用StandardOutput.ReadLine()
来读取该行,然后检查它是否包含"(config-if"
。
我希望这有帮助!
答案 1 :(得分:0)
经过几天的研究,我想我遇到了一个答案 - 我决定在这里分享一下,因为我不是唯一一个碰到这个问题的人。也许我的努力对某人有用。首先,我会发一个简短的答案,之后,我会发表我的研究和解释。由于我不认为自己是C#或Dot Net Guru,我非常乐意在这方面进行社区合作,纠正和改进这个答案。这样我们就可以让每个人都更好地使用StackOverfllow,不是吗? :)
关于它,你没什么可以做的。这种死锁似乎是实现同步读取的方式所固有的(我正在使用.Net 4.0 Framework),因此如果可以的话 - 首先避免遇到麻烦并且更喜欢异步读取。由于您的代码可能在您的PC(=开发环境)上运行,但未能部署到IIS,因为它与我完全一样。可能唯一可以使用的解决方法,就是当您的预期输出(=您确定(!)有输出,等待变红)以最终模式结束时,您可以识别并且停止阅读。
当您尝试从标准输出读取时,当没有任何东西在那里等待您时,问题会出现。
当(a)首先没有输出或(b)你刚读完那里的东西并且“前进到下一个”(不存在的)字符或字符串时,就会出现这种情况。虽然(b)更危险恕我直言,因为当你期望没有输出时很容易不读,但更难以停止,当你没有条件让你知道什么时候(至少,我无法通过调试我找到这样的代码并记录在MSDN中 - 我的问题上的沉默是另一个证据。
乍一看,您可以使用Peek()方法,它承诺“返回下一个可用的字符,但不会消耗它”,并且您可以轻松地在Web上找到示例,当使用Peek()时似乎可以特技。不幸的是,MSDN还说“如果没有要读取的字符则为-1,如果流不支持搜索,则为”。那么,至少在我的情况下,标准输出不支持搜索。因此,Peek()相当无法使用。它确实工作了几次(也许有更深入理解的人可以解释原因),但我怀疑在这种情况下我没有得到整个输出。
现在,我想迭代我使用过的方法及其结果,这样你就可以从我的研究中学习并知道你的代码会发生什么:
在我看来,当前的实现或Process.StandardOutput缺少任何识别何时红色全部存在的方法。这就是为什么在我看来,Read()和ReadByte()之外的所有方法都会挂起。如果你跨过当前的流边缘,这两个也会挂起。在我的情况下,我能够转移到SSH.Net(我要感谢那个精彩项目的贡献者)。顺便说一下,它永远不会挂起在sshReader.ReadToEnd():)
PPS:我的开发环境让您感到疑惑:使用Framework 4在Windows 7 64位和IIS 8(干净安装)上安装VisualStudio 2010 Ultimate。