c# - 如何写入标准输入/从 SSH 连接的远程进程的标准输出读取? (Renci.SshNet)

标签 c# ssh

我想连接一个 SSH 服务器,在连接时运行一个自定义命令,该命令需要 XML 作为输入(UTF-8 编码,多行,在每个 XML 文档的末尾有一个特殊的行标记它的结束)和输出 XML(UTF-8 编码,多行,末尾有相同的特殊行表示文档结束)。

目前有一种使用 plink.exe(以 PuTTy 闻名)的机制有效(意思是:服务器端确实按规定工作),但我正在消除对外部进程的需求。

我尝试使用 Renci.SshNet 库,但我发现文档不充分,并且找不到我需要的示例。

到目前为止我的尝试:

using System;
using Renci.SshNet;

namespace ServerConnect
{
    public class ServerConnection
    {
        private const string EOC= "*-* COMMAND DELIMITER *-*";
        private SshClient scon;
        private System.IO.Stream stdin, stdout, stderr;
        private System.IO.StreamWriter stdin_writer;
        private System.IO.StreamReader stdout_reader;
        private Shell shell;

        public ServerConnection (string keyFileName, string keyFilePassphrase)
        {
            ConnectionInfo ci= new ConnectionInfo("my.server.local", 22, "datamgr",
                                                  new PrivateKeyAuthenticationMethod("datamgr", new PrivateKeyFile(keyFileName, keyFilePassphrase)));
            this.scon= new SshClient(ci);
        }

        public ServerConnection (string keyFilePassphrase): this("client_id_rsa", keyFilePassphrase) {}

        public void Connect() {
            this.scon.Connect();
            this.stdin= new System.IO.MemoryStream();
            this.stdin_writer= new System.IO.StreamWriter(stdin);
            this.stdout= new System.IO.MemoryStream();
            this.stdout_reader= new System.IO.StreamReader(stdout);
            this.stderr= new System.IO.MemoryStream();
            this.shell= this.scon.CreateShell(this.stdin, this.stdout, this.stderr);
            this.shell.Start();
        }

        public void Disconnect() {
            this.scon.Disconnect();
        }

        public string Command(string text) {
            Console.WriteLine("sending command");
            this.stdin_writer.WriteLine(text);
            Console.WriteLine("sending EOC");
            this.stdin_writer.WriteLine(EOC);
            this.stdin_writer.Flush();
            for (;;) {
                string line;
                line= this.stdout_reader.ReadLine();
                if (line == null) {
                    Console.WriteLine("got null");
                    break;
                }
                Console.WriteLine("READ");
                Console.WriteLine(line);
                if (line.StartsWith(EOC)) break;
            }
            return ""; // yes, this should return the built output
        }
    }
}

鉴于这是一个程序集,我正处于尝试连接到服务器的阶段(为方便起见,测试通过 booish 运行):

>>> import ServerConnect
>>> a= ServerConnection("passphrase")
ServerConnect.ServerConnection
>>> a.Connect()
>>> a.Command("<i command=\"ping\"/>")
sending command
sending EOC
got null
''

我可以看到(在服务器的 auth.log 中)连接是在 a.Connect() 调用之后建立的。但是,似乎无论我写入 stdin_writer 都不会发送到服务器。

我怎样才能实现这个机制?向服务器发送数据,然后发送分隔符,然后读取数据,直到我读取分隔符?该循环将在一次连接期间重复多次。

请注意,我不是经验丰富的 C# 程序员,因此我可能缺乏对 C# 流模型的基本了解。

PS 我看过this答案,但似乎 CreateShellStream 调用 block ,可能在 PseudoTty 分配中(该过程不需要伪 ttys,只需要输入/输出)。

PS2 我从 codeplex.com 下载并编译了最新版本的 Renci.SshNet,现在我在这一点上(Connect 方法摘录):

this.scon.Connect();
this.stream= this.scon.CreateShellStream("dumb", 80, 24, 800, 600, 1024);
this.stdin_writer= new System.IO.StreamWriter(this.stream);
this.stdout_reader= new System.IO.StreamReader(this.stream);
this.shell= this.scon.CreateShell(this.stream, this.stream, this.stream);
this.shell.Start();

但是,对 stdin_writer 的任何写入(以及随后的刷新)似乎都没有通过。

最佳答案

抱歉,输入此内容后我发现我在发帖...

你可以使用这里给出的解决方案,这是我想做类似你的事情时使用的:

Renci ssh.net - Create console screen from form when connected

您可以放弃使用任何 System.IO 对象并使用 ShellStream 对象操纵 SSH session IO。

ShellStream.Expect 将读取输出,并查找特定的字符串。 ShellStream.WriteLine 会将输入发送到 shell。

        string reply = string.Empty;
        ShellStream ss = scon.CreateShellStream("dumb", 80, 24, 800, 600, 1024);

        reply = ss.Expect("Press enter to continue");  //The prompt I get after login
        ParseOutput(reply);

        ss.WriteLine("./myscript.sh")
        reply = ss.Expect("$"); //My prompt, when the script has finished.
        ParseOutput(reply);

ParseOutput 是我编写的一个例程,用于在每个换行符处拆分“回复”字符串,并将每一行添加到表单的列表框中。

关于c# - 如何写入标准输入/从 SSH 连接的远程进程的标准输出读取? (Renci.SshNet),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30079526/

相关文章:

vim - 从 Mac OS X 通过 SSH 突出显示 PHP 语法

c# - ASP.NET MVC - 创建没有后备的自定义路由

c# - Process.Start 不适用于 Filezilla 的 UNC 路径

c# - 没有控制台窗口的 AppServiceBridge

ssh - OpenStack:通过 SSH 连接到 VM 时权限被拒绝(公钥)

azure - 通过 SSH 对同一主机但不同端口上的 Azure VM 进行 Ansible 访问

c# - ASP.NET 中的 GridView 问题

c# - C#中的Base 64编码

ssh - 由另一个用户向服务器添加ssh公钥

git - SSH - 通过 CMD 拒绝权限(无法验证 git@github.com)