2013-03-31 27 views
0

我有一个Windows服务将处理来自plink.exe(Putty/SSH的东西)的结果。我目前正在成功捕获标准输出并通过标准输入发送命令给进程。Process.Start捕获标准输出字符

我的问题是,似乎是OutputDataReceived事件没有得到上升,直到我收到从控制台应用程序换行符。该过程会提示输入密码,直到输入密码后才会有换行符。

所以我的问题是,有没有办法处理标准输出字符的字符,而不是从System.Diagnostics.Process类逐行?

这里是我的代码:

_processInfoTest = new ProcessStartInfo(); 
_processInfoTest.FileName = serviceSettings.PlinkExecutable; 
_processInfoTest.Arguments = GetPlinkArguments(serviceSettings); 
_processInfoTest.RedirectStandardOutput = true; 
_processInfoTest.RedirectStandardError = true; 
_processInfoTest.RedirectStandardInput = true; 
_processInfoTest.UseShellExecute = false; 
_processInfoTest.CreateNoWindow = true; 

_processTest = new Process(); 
_processTest.StartInfo = _processInfoTest; 
_processTest.OutputDataReceived += processTest_OutputDataReceived; 
_processTest.ErrorDataReceived += processTest_OutputDataReceived; 
_processTest.Start(); 

_processTest.BeginOutputReadLine(); 
_processTest.BeginErrorReadLine(); 

而且,处理文本的输入线的事件处理程序:

private static void processTest_OutputDataReceived(object sender, DataReceivedEventArgs e) 
{ 
    string line = e.Data; 

    if (line != null) 
    { 
     WcfServerHelper.BroadcastRemoteCallback(x => x.PlinkTextOutput(line, DateTime.Now)); 

     if (line.Contains("If you do not trust this host, press Return to abandon the")) 
     { 
      _processTest.StandardInput.Write("y"); 
      _processTest.StandardInput.Write("\n"); 
      _processTest.StandardInput.Flush(); 
     } 

     // This code never gets called because the event doesn't get raised until a line-break occurs 
     if (line.Contains("'s password:")) 
     { 
      _processTest.StandardInput.Write("mypassword"); 
      _processTest.StandardInput.Write("\n"); 
      _processTest.StandardInput.Flush(); 
     } 

     if (line.Contains("Access granted")) 
     { 
      if (!_processTest.HasExited) 
       _processTest.Kill(); 

      WcfServerHelper.BroadcastRemoteCallback(x => x.TestConnectionCallback(PlinkStatus.Success)); 
     } 
     else if (line.Contains("Access denied") || line.Contains("Password authentication failed")) 
     { 
      if (!_processTest.HasExited) 
       _processTest.Kill(); 

      WcfServerHelper.BroadcastRemoteCallback(x => x.TestConnectionCallback(PlinkStatus.InvalidUserOrPass)); 
     } 
     else if (line.Contains("Host does not exist")) 
     { 
      if (!_processTest.HasExited) 
       _processTest.Kill(); 

      WcfServerHelper.BroadcastRemoteCallback(x => x.TestConnectionCallback(PlinkStatus.InvalidHostname)); 
     } 
     else if (line.Contains("Connection timed out")) 
     { 
      if (!_processTest.HasExited) 
       _processTest.Kill(); 

      WcfServerHelper.BroadcastRemoteCallback(x => x.TestConnectionCallback(PlinkStatus.TimedOut)); 
     } 
    } 
} 

谢谢!

回答

1

我一直在寻找一个永远的答案,并在问这个问题后,我找到了我的解决方案。

顺便说一句,感谢DarkSquirrel,你打在头上的钉子。

这里是我的解决方案:

_processInfoTest = new ProcessStartInfo(); 
_processInfoTest.FileName = serviceSettings.PlinkExecutable; 
_processInfoTest.Arguments = GetPlinkArguments(serviceSettings); 
_processInfoTest.RedirectStandardOutput = true; 
_processInfoTest.RedirectStandardError = true; 
_processInfoTest.RedirectStandardInput = true; 
_processInfoTest.UseShellExecute = false; 
_processInfoTest.CreateNoWindow = true; 

WcfServerHelper.BroadcastRemoteCallback(x => x.PlinkTextOutput(_processInfoTest.Arguments, DateTime.Now)); 

_processTest = new Process(); 
_processTest.StartInfo = _processInfoTest; 
_processTest.Start(); 

Task.Factory.StartNew(() => 
    { 
     ProcessOutputCharacters(_processTest.StandardError); 
    }); 

Task.Factory.StartNew(() => 
    { 
     ProcessOutputCharacters(_processTest.StandardOutput); 
    }); 

而且我的方法:

private static void ProcessOutputCharacters(StreamReader streamReader) 
{ 
    int outputCharInt; 
    char outputChar; 
    string line = string.Empty; 

    while (-1 != (outputCharInt = streamReader.Read())) 
    { 
     outputChar = (char)outputCharInt; 
     if (outputChar == '\n' || outputChar == '\r') 
     { 
      if (line != string.Empty) 
      { 
       ProcessLine("Output: " + line); 
      } 

      line = string.Empty; 
     } 
     else 
     { 
      line += outputChar; 

      if (line.Contains("login as:")) 
      { 
       _processTest.StandardInput.Write("myusername"); 
       _processTest.StandardInput.Write("\n"); 
       _processTest.StandardInput.Flush(); 
      } 

      if (line.Contains("'s password:")) 
      { 
       _processTest.StandardInput.Write("mypassword"); 
       _processTest.StandardInput.Write("\n"); 
       _processTest.StandardInput.Flush(); 
      } 
     } 
    } 
} 

private static void ProcessLine(string line) 
{ 
    if (line != null) 
    { 
     WcfServerHelper.BroadcastRemoteCallback(x => x.PlinkTextOutput(line, DateTime.Now)); 

     if (line.Contains("If you do not trust this host, press Return to abandon the")) 
     { 
      _processTest.StandardInput.Write("y"); 
      _processTest.StandardInput.Write("\n"); 
      _processTest.StandardInput.Flush(); 
     } 

     if (line.Contains("Access granted")) 
     { 
      if (!_processTest.HasExited) 
       _processTest.Kill(); 

      WcfServerHelper.BroadcastRemoteCallback(x => x.TestConnectionCallback(PlinkStatus.Success)); 
     } 
     else if (line.Contains("Access denied") || line.Contains("Password authentication failed")) 
     { 
      if (!_processTest.HasExited) 
       _processTest.Kill(); 

      WcfServerHelper.BroadcastRemoteCallback(x => x.TestConnectionCallback(PlinkStatus.InvalidUserOrPass)); 
     } 
     else if (line.Contains("Host does not exist")) 
     { 
      if (!_processTest.HasExited) 
       _processTest.Kill(); 

      WcfServerHelper.BroadcastRemoteCallback(x => x.TestConnectionCallback(PlinkStatus.InvalidHostname)); 
     } 
     else if (line.Contains("Connection timed out")) 
     { 
      if (!_processTest.HasExited) 
       _processTest.Kill(); 

      WcfServerHelper.BroadcastRemoteCallback(x => x.TestConnectionCallback(PlinkStatus.TimedOut)); 
     } 
    } 

} 

我唯一的问题是现在当我发送的用户名和密码(通过StandardInput),它只是在发送前5字符。如果需要的话,我会针对这个问题做一些研究并发布一个单独的问题。

谢谢!

1

您正在使用行缓冲的情况下...你将不得不实现自己的读者,在StreamReader的调用read()/ ReadAsync()让每一个字符...