在C#中使用Streams用于SSH库

时间:2017-10-23 22:41:15

标签: c# stream ssh.net

我正在使用C#和SSH.NET开发类似Putty的用户交互式SSH UI,这是一个用于建立SSH连接的开源库。我遇到的问题是,我能够找到所有示例的工作方式,它们似乎创建了一个新连接,或者以非交互模式执行,这意味着在先前命令中执行的任何操作都不会延续到以下命令。

我基本上不习惯使用流 - 在SSH.NET库中有一些方法似乎是使用流打开shell,这样你就可以将流分配给stdin,stdout和stderr,但在尝试使用时它们,我找不到关于如何设置流以将它们提供给方法调用的好信息。

  1. 我是否以原始溪流喂养?
  2. 我使用MemoryStream还是TextStream
  3. 以下是SSH.NET中CreateShell类中SshClient方法的简短定义:

    public Shell CreateShell(Stream input, Stream output, Stream extendedOutput)
    {
        return CreateShell(input, output, extendedOutput, string.Empty, 0, 0, 0, 0, null, 1024);
    }
    

    使用的长覆盖版本:

    public Shell CreateShell(Stream input, Stream output, Stream extendedOutput, string terminalName, uint columns, uint rows, uint width, uint height, IDictionary<TerminalModes, uint> terminalModes, int bufferSize)
    {
        EnsureSessionIsOpen();
    
        return new Shell(Session, input, output, extendedOutput, terminalName, columns, rows, width, height, terminalModes, bufferSize);
    }
    

    在设置正确的连接流之后,我该如何读取和写入它们?我是否需要设置StreamReader和/或StreamWriter来访问流?我已经这样做了,以便在使用StdErr方法使用现有SshCommand对象后阅读.Execute(),但我不确定如何将其与预先存在的流绑定我创造的。

    ShellStream类

    最后,还有另一个选项似乎与单个Stream对象建立连接 - 但我不确定这是否仅用于单元测试,或者它是否适用于“正常”操作:

    public ShellStream CreateShellStream(string terminalName, uint columns, uint rows, uint width, uint height, int bufferSize, IDictionary<TerminalModes, uint> terminalModeValues)
    {
        EnsureSessionIsOpen();
    
        return ServiceFactory.CreateShellStream(Session, terminalName, columns, rows, width, height, terminalModeValues, bufferSize);
    }
    

    ShellStream : Stream类看起来也是一个很好的候选者,覆盖StreamCanReadCanSeek,{CanWrite的基础Flush类{1}},LengthReadWrite

    以下是ShellStream类的基本定义,包含属性和构造函数:

    public class ShellStream : Stream
    {
        private const string CrLf = "\r\n";
    
        private readonly ISession _session;
        private readonly Encoding _encoding;
        private readonly int _bufferSize;
        private readonly Queue<byte> _incoming;
        private readonly Queue<byte> _outgoing;
        private IChannelSession _channel;
        private AutoResetEvent _dataReceived = new AutoResetEvent(false);
        private bool _isDisposed;
    
        /// <summary>
        /// Occurs when data was received.
        /// </summary>
        public event EventHandler<ShellDataEventArgs> DataReceived;
    
        /// <summary>
        /// Occurs when an error occurred.
        /// </summary>
        public event EventHandler<ExceptionEventArgs> ErrorOccurred;
    
        /// <summary>
        /// Gets a value that indicates whether data is available on the <see cref="ShellStream"/> to be read.
        /// </summary>
        /// <value>
        /// <c>true</c> if data is available to be read; otherwise, <c>false</c>.
        /// </value>
        public bool DataAvailable
        {
            get
            {
                lock (_incoming)
                {
                    return _incoming.Count > 0;
                }
            }
        }
    
        /// <summary>
        /// Gets the number of bytes that will be written to the internal buffer.
        /// </summary>
        /// <value>
        /// The number of bytes that will be written to the internal buffer.
        /// </value>
        internal int BufferSize
        {
            get { return _bufferSize; }
        }
    
    
        /// <summary>
        /// Initializes a new <see cref="ShellStream"/> instance.
        /// </summary>
        /// <param name="session">The SSH session.</param>
        /// <param name="terminalName">The <c>TERM</c> environment variable.</param>
        /// <param name="columns">The terminal width in columns.</param>
        /// <param name="rows">The terminal width in rows.</param>
        /// <param name="width">The terminal height in pixels.</param>
        /// <param name="height">The terminal height in pixels.</param>
        /// <param name="terminalModeValues">The terminal mode values.</param>
        /// <param name="bufferSize">The size of the buffer.</param>
        internal ShellStream(ISession session, string terminalName, uint columns, uint rows, uint width, uint height, IDictionary<TerminalModes, uint> terminalModeValues, int bufferSize)
        {
            _encoding = session.ConnectionInfo.Encoding;
            _session = session;
            _bufferSize = bufferSize;
            _incoming = new Queue<byte>();
            _outgoing = new Queue<byte>();
    
            _channel = _session.CreateChannelSession();
            _channel.DataReceived += Channel_DataReceived;
            _channel.Closed += Channel_Closed;
            _session.Disconnected += Session_Disconnected;
            _session.ErrorOccured += Session_ErrorOccured;
    
            _channel.Open();
            _channel.SendPseudoTerminalRequest(terminalName, columns, rows, width, height, terminalModeValues);
            _channel.SendShellRequest();
        }
    

0 个答案:

没有答案