我没有得到PLINK的完整STDOUT
。
我有以下方法,它运行plink-application(基于控制台的PuTTY)
但是,当我使用sychron调用启动方法时,我没有获得plink的完整标准输出。
当我启动一个新线程(只运行具有相同参数的方法)时,我得到整个输出(但不是在所有环境中)。
我没有更多的想法,我怎么能确定,我有完整的输出。
注意:我想读取输出,但最后还没有换行符(\n
)。所以我不能使用DataReceived
- 事件。
private static string runPlinkToEnd(string param, string action, string text, Action callbackOnSucess, Action callbackOnError)
{
//Lock
lock (_lockExecutions)
{
_isRunning = true;
_lastServerAction = text;
_outputLines = new List<string>();
CancellationTokenSource cancel = new CancellationTokenSource(); ;
//Setup Param
param = string.Format("{0} \"{1}\"", param, action);
_outputLines.Add(string.Format("PLINK STARTED AT {0} WITH '{1}'", DateTime.Now.ToString(), param));
_outputLines.Add("\t");
//Setup Process
ProcessStartInfo starter = new ProcessStartInfo(_plink.FullName, param);
starter.CreateNoWindow = true;
starter.UseShellExecute = false;
starter.RedirectStandardError = true;
starter.RedirectStandardOutput = true;
starter.StandardOutputEncoding = Encoding.GetEncoding(850);
starter.StandardErrorEncoding = Encoding.GetEncoding(850);
//Start Process
Process plinkInstance = new Process();
plinkInstance.StartInfo = starter;
plinkInstance.EnableRaisingEvents = true;
//start Timer for timeout
var timer = new System.Timers.Timer(20000);
timer.AutoReset = false;
timer.Elapsed += (sender, e) => { timeout(cancel, plinkInstance, callbackOnError); }; //timeout() trigger cancelation-token and kill instance
timer.Start();
plinkInstance.Start();
//Read async
//readUntilEnd() reads char-by-char from stream
Task.Factory.StartNew(() => readUntilEnd(plinkInstance.StandardOutput, timer, cancel.Token), cancel.Token);
Task.Factory.StartNew(() => readUntilEnd(plinkInstance.StandardError, timer, cancel.Token), cancel.Token);
plinkInstance.Exited += (sender, e) =>
{
//if timer still running, plink has exited
if (timer.Enabled)
{
Thread.Sleep(2000);
cancel.Cancel();
Thread.Sleep(200);
timer.Stop();
_outputLines.Add(string.Format("PLINK ENDS AT{0}", DateTime.Now.ToString()));
callbackOnSucess.Invoke();
}
// when timer stops, timeout-timer has triggered the exit
else
{
_outputLines.Add(string.Format("PLINK TIMEOUT AT {0}", DateTime.Now.ToString()));
callbackOnError.Invoke();
}
_isRunning = false;
};
//wait for end
plinkInstance.WaitForExit();
Thread.Sleep(1000);
}//End lock
return string.Join("\n", _outputLines);
}
private static void readUntilEnd(StreamReader stream, System.Timers.Timer timer, CancellationToken canelToken)
{
char[] buffer = new char[1];
Task task = stream.ReadAsync(buffer, 0, 1);
int cooldown = 5;
bool thisReaded = false;
while (!canelToken.IsCancellationRequested)
{
if (task.IsCompleted && (thisReaded == _readed))
{
if (buffer[0] != '\0')
{
readAChar(buffer[0]);
buffer[0] = '\0';
// reset timeout-timer
if (_isRunning)
{
timer.Stop();
timer.Start();
}
cooldown = 0;
lock (_lockWrite)
_readed = true;
thisReaded = true;
}
task = stream.ReadAsync(buffer, 0, 1);
}
else if (!task.IsCompleted)
{
if (cooldown < 100)
cooldown++;
if (thisReaded && cooldown > 5)
{
thisReaded = false;
_readed = false;
}
}
if (cooldown > 0)
Thread.Sleep(cooldown);
}
}
private static void readAChar(char c)
{
if (c == '\n')
_outputLines.Add("\t");
else if (c != '\0')
{
int last = _outputLines.Count -1;
_outputLines[last] = _outputLines[last] + c;
}
}