流程阅读数据不可靠

时间:2018-04-03 09:24:40

标签: c#

简短说明

我没有得到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;
    }
}

0 个答案:

没有答案