SSH.NET实时命令输出监控 [英] SSH.NET real-time command output monitoring

查看:66
本文介绍了SSH.NET实时命令输出监控的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在远程 Linux 机器上有一个长时间运行的脚本 script.sh.我需要启动它并实时监控它的活动.脚本在其活动期间可能会输出到 stdoutstderr.我正在寻找一种方法来捕获这两个流.

There is a long running script script.sh on a remote Linux machine. I need to start it and monitor it's activity in real time. The script during it's activity may output to stdout and stderr. I am searching for a way to capture both of the streams.

我使用 Renci SSH.NET 上传 script.sh 并启动它,所以很高兴看到绑定到这个库的解决方案.在我看来,完美的解决方案是新方法:

I use Renci SSH.NET to upload script.sh and start it, so it would be great to see a solution bounded to this library. In my mind the perfect solution is the new method:

var realTimeScreen= ...;

var commandExecutionStatus = sshClient.RunCommandAsync(
    command: './script.sh',
    stdoutEventHandler: stdoutString => realTimeScreen.UpdateStdout(stdString)
    stderrEventHandler: stderrString => realTimeScreen.UpdateStderr(stderrString));
...
commandExecutionStatus.ContinueWith(monitoringTask =>
{
    if (monitoringTask.Completed)
    {
        realTimeScreen.Finish();
    }
});

推荐答案

所以,这是我想出的解决方案.当然,它可以改进,所以它是开放的批评.
我用过

So, here is the solution I came up with. Of course, it can be improved, so it is open to critique.
I used

await Dispatcher.Yield(DispatcherPriority.ApplicationIdle);

而不是 Task.Yield() 因为 Task.Yield() 将使延续比 GUI 事件具有更高的优先级,但是,作为一个坏结果,它要求您使用 WindowsBase.dll 的应用程序.

instead of Task.Yield() because Task.Yield() will make continuation a higher priority than GUI events, but, as a bad consequence, it demands your application to use WindowsBase.dll.

public static class SshCommandExtensions
{
    public static async Task ExecuteAsync(
        this SshCommand sshCommand,
        IProgress<ScriptOutputLine> progress,
        CancellationToken cancellationToken)
    {
        var asyncResult = sshCommand.BeginExecute();
        var stdoutStreamReader = new StreamReader(sshCommand.OutputStream);
        var stderrStreamReader = new StreamReader(sshCommand.ExtendedOutputStream);

        while (!asyncResult.IsCompleted)
        {
            await CheckOutputAndReportProgress(
                sshCommand,
                stdoutStreamReader,
                stderrStreamReader,
                progress,
                cancellationToken);

            await Dispatcher.Yield(DispatcherPriority.ApplicationIdle);
        }

        sshCommand.EndExecute(asyncResult);

        await CheckOutputAndReportProgress(
            sshCommand,
            stdoutStreamReader,
            stderrStreamReader,
            progress,
            cancellationToken);
    }

    private static async Task CheckOutputAndReportProgress(
        SshCommand sshCommand,
        TextReader stdoutStreamReader,
        TextReader stderrStreamReader,
        IProgress<ScriptOutputLine> progress,
        CancellationToken cancellationToken)
    {
        if (cancellationToken.IsCancellationRequested)
        {
            sshCommand.CancelAsync();
        }
        cancellationToken.ThrowIfCancellationRequested();

        await CheckStdoutAndReportProgressAsync(stdoutStreamReader, progress);
        await CheckStderrAndReportProgressAsync(stderrStreamReader, progress);
    }

    private static async Task CheckStdoutAndReportProgressAsync(
        TextReader stdoutStreamReader,
        IProgress<ScriptOutputLine> stdoutProgress)
    {
        var stdoutLine = await stdoutStreamReader.ReadToEndAsync();

        if (!string.IsNullOrEmpty(stdoutLine))
        {
            stdoutProgress.Report(new ScriptOutputLine(
                line: stdoutLine,
                isErrorLine: false));
        }
    }

    private static async Task CheckStderrAndReportProgressAsync(
        TextReader stderrStreamReader,
        IProgress<ScriptOutputLine> stderrProgress)
    {
        var stderrLine = await stderrStreamReader.ReadToEndAsync();

        if (!string.IsNullOrEmpty(stderrLine))
        {
            stderrProgress.Report(new ScriptOutputLine(
                line: stderrLine,
                isErrorLine: true));
        }
    }
}

public class ScriptOutputLine
{
    public ScriptOutputLine(string line, bool isErrorLine)
    {
        Line = line;
        IsErrorLine = isErrorLine;
    }

    public string Line { get; private set; }

    public bool IsErrorLine { get; private set; }
}

这篇关于SSH.NET实时命令输出监控的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆