使用 Renci.SshNet 通过 ssh 连接读取输出流

Read in output stream through ssh connection using Renci.SshNet

我看过很多其他的堆栈溢出帖子,但 none 其中确实与我想要完成的相似。基本上,我试图通过 SSH 连接连接到设备 运行 Windows CE,并捕获打印到终端的任何输出。当我使用 Putty 通过 ssh 连接时,我可以在终端中看到许多用于调试的打印语句。我正在尝试捕获这些调试语句并在我的 wpf 应用程序中使用它们。这些调试语句不是对命令的响应,它们只是打印到终端。

到目前为止,我能够发送命令并收到单个响应,但我正在寻找的是能够无限期地接收响应,直到用户关闭连接或应用程序。

我正在使用 Renci.SshNet 发送我的命令,但我一直在使用 ShellStream,但无法使其正常工作。这是我目前所拥有的:

using System;
using System.Threading;
using System.Windows;
using Renci.SshNet;

namespace TestSshConsole
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private SshClient _sshConnection;
        private ShellStream _shellStream;
        private delegate void UpdateTextCallback(string message);

        public MainWindow()
        {
            InitializeComponent();
        }

        /// <summary>
        /// When the user presses connect, connect to the device
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                // Connect to device
                _sshConnection = new SshClient(hostname.Text, int.Parse(port.Text), username.Text, password.Text);
                _sshConnection.Connect();

                // Create a shell stream
                _shellStream = _sshConnection.CreateShellStream("test", 80, 60, 800, 600, 65536);

                MessageBox.Show("Connected!");
            }
            catch (Exception exception)
            {
                MessageBox.Show($"Error {exception.Message}");
            }
        }

        /// <summary>
        /// Start a new thread used to receive SSH data when the window is loaded
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            ThreadStart threadStart = new ThreadStart(RecvSshData);
            Thread thread = new Thread(threadStart);

            thread.IsBackground = true;
            thread.Start();
        }

        /// <summary>
        /// Receive SSH data and write it to the textbox
        /// </summary>
        private void RecvSshData()
        {
            while (true)
            {
                try
                {
                    if (_shellStream != null && _shellStream.DataAvailable)
                    {
                        string data = _shellStream.Read();

                        textBox.Dispatcher.Invoke(new UpdateTextCallback(UpdateText), data);
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine(e);
                }

                Thread.Sleep(200);
            }
        }

        /// <summary>
        /// Write message to the textbox
        /// </summary>
        /// <param name="message"></param>
        private void UpdateText(string message)
        {
            textBox.AppendText(message + "\r\n");
        }
    }
}

从我在其他帖子中读到的内容来看,这似乎应该有效并且应该捕获所有数据,但它没有。我在实施过程中可能做错了什么,或者他们甚至可能是更好的方法。

欢迎提供任何帮助或建议。

我在一定程度上让它发挥了作用。 "StartRecording" 开始在一个单独的线程上记录流,该线程现在可以将其写入控制台。这能够接收打印到我设备上的终端的所有数据。

我现在遇到的唯一问题是数据在大约一分钟后停止传输。我不确定发生了什么,但我认为 ShellStream 在某个时候断开连接,我不确定为什么。

private SshClient _sshClient;
private ShellStream _shellStream;
private StreamReader _reader;
private StreamWriter _writer;

public Recorder()
{
    try
    {
        _sshClient = new SshClient(_hostname, _port, _username, _password);
        _sshClient.Connect();

        _shellStream = _sshClient.CreateShellStream("Terminal", 80, 60, 800, 600, 65536);

        _reader = new StreamReader(_shellStream, Encoding.UTF8, true, 1024, true);
        _writer = new StreamWriter(_shellStream) { AutoFlush = true };
    }
    catch (Exception e)
    {
        // TODO
        Console.WriteLine(e);
    }
}

/// <summary>
/// Begin recording the output of "routediagnostic on" command
/// </summary>
public void StartRecording()
{
    try
    {
        IsRecording = true;
        WriteStream("routediagnostic on");

        // Start a background thread that will read in the data from the Pyng terminal
        ThreadStart threadStart = ReceiveData;
        Thread thread = new Thread(threadStart) {IsBackground = true};
        thread.Start();
    }
    catch (Exception e)
    {
        // TODO
        Console.WriteLine(e);
    }
    finally
    {
        IsRecording = false;
    }
}

private void ReceiveData()
{
    while (true)
    {
        try
        {
            if (_reader != null)
            {
                StringBuilder result = new StringBuilder();

                string line;
                while ((line = _reader.ReadLine()) != null)
                {
                    result.AppendLine(line);
                }

                if (!string.IsNullOrEmpty(result.ToString()))
                {
                    // TODO - Parse data at this point
                    Console.WriteLine(result.ToString());
                }
            }
        }
        catch (Exception e)
        {
            // TODO
            Console.WriteLine(e);
        }

        Thread.Sleep(200);
    }
}

private void WriteStream(string cmd)
{
    _writer.WriteLine(cmd);
    while (_shellStream.Length == 0)
    {
        Thread.Sleep(500);
    }
}