2013-03-31 61 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()讓每一個字符...

相關問題