[英]Process.Start capturing standard output characters
我有一個Windows服務,將處理來自plink.exe(Putty / SSH的東西)的結果。 我目前正成功捕獲標准輸出並通過標准輸入向過程發送命令。
我的問題是,在我從控制台應用程序進程收到換行符之前, 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));
}
}
}
謝謝!
您正在使用的事件是行緩沖...您必須實現自己的讀取器,在流讀取器上調用Read()/ ReadAsync()以獲取每個char ...
我一直在尋找答案,在問這里問題之后,我找到了解決辦法。
順便說一句,感謝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個字符。 我將對這個問題進行一些研究,如果需要的話,將其作為一個單獨的問題發布。
謝謝!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.