Чтение в потоке вывода через ssh соединение с использованием Renci.SshNet - PullRequest
0 голосов
/ 22 октября 2018

Я просмотрел множество других сообщений о переполнении стека, но ни одно из них не было похоже на то, что я пытаюсь выполнить.По сути, я пытаюсь подключиться к устройству под управлением Windows CE через соединение SSH и перехватить любой вывод, который выводится на терминал.Когда я подключаюсь через ssh, используя Putty, я вижу много операторов print в терминале, которые используются для отладки.Я пытаюсь перехватить эти отладочные операторы и использовать их в своем приложении 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");
        }
    }
}

Из того, что я прочитал в других постах, кажется, что это должно работать и должно захватывать все данные, но это не так.Возможно, я что-то не так делаю в своей реализации, или это может быть лучший способ сделать это.

Любой вклад с помощью или рекомендациями приветствуется.

1 Ответ

0 голосов
/ 25 октября 2018

Я получил это до определенной степени.«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);
    }
}
...