同步读取挂起

时间:2017-10-01 21:18:40

标签: c# asp.net plink

过去几天,我正在尝试使以下代码同步工作:

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处的其他方式。

2 个答案:

答案 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()相当无法使用。它确实工作了几次(也许有更深入理解的人可以解释原因),但我怀疑在这种情况下我没有得到整个输出。

现在,我想迭代我使用过的方法及其结果,这样你就可以从我的研究中学习并知道你的代码会发生什么:

  • Stream(!StreamReader.EndOfStream)中的StreamReader.Read() - 挂起 执行时
  • Stream内的StreamReader.Read()(StreamReader.Peek()> -1) - 跳过循环
  • StreamReader.ReadLine() - 执行时挂起
  • StreamReader.ReadToEnd() - 执行时挂起
  • StreamReader.BaseStream.Length - 运行时异常:Stream不支持搜索
  • StreamReader.Read()/ StreamReader.BaseStream.ReadByte() - 一个特例,我得出结论 - 两者都读得很好,直到读完当前缓冲区结束后的下一个字符。比挂起。

在我看来,当前的实现或Process.StandardOutput缺少任何识别何时红色全部存在的方法。这就是为什么在我看来,Read()和ReadByte()之外的所有方法都会挂起。如果你跨过当前的流边缘,这两个也会挂起。在我的情况下,我能够转移到SSH.Net(我要感谢那个精彩项目的贡献者)。顺便说一下,它永远不会挂起在sshReader.ReadToEnd():)

PPS:我的开发环境让您感到疑惑:使用Framework 4在Windows 7 64位和IIS 8(干净安装)上安装VisualStudio 2010 Ultimate。