【问题标题】:Sending input during command output with SSH.NET使用 SSH.NET 在命令输出期间发送输入
【发布时间】:2017-11-13 11:49:35
【问题描述】:

使用 PuTTY,我连接到 SSH 服务器,然后执行一个不断输出日志的命令(每秒多行)。在此过程中,我可以发送一些作为命令的击键,即。输入123Esc 以停止该过程。如果我输入了一个有效的击键,我可以在输出设备上看到它,所以我总是知道击键是否被发送。

我想以编程方式执行此操作 - 连接到 SSH 服务器,执行主命令,然后将一些击键作为命令发送给它,同时监控日志,在其中我可以看到对我的命令的响应。

所以我想用 SSH.NET 来做这件事——它是一个简洁的 SSH 工具,输出可靠,而且很好用。但是我有一个问题 - 我可以连接到这个服务器,执行一个命令,但是当它转储日志时,我无法向它发送任何击键。

我尝试过使用CreateShellStream的方式:

  • shellStream.WriteLine('keystroke in ascii or just string')
  • sshClient.CreateCommand('keystroke in ascii or just string') 然后sshClient.Execute();
  • 使用StreamWriter(shellstream) 并写信给它

我尝试过 ascii 代码、UTF-16 代码、字符串,但不幸的是没有任何效果。

使用 Plink(PuTTY 命令行工具)做的同样的事情工作得很好,但它更混乱,我更喜欢使用 SSH.NET。你知道使用 SSH.NET 和 Plink 发送击键有什么区别吗?为什么它与 Plink 完美配合?我试过用 Wireshark 调试它,不幸的是 SSH 很难做到。

对于 Plink,我基本上使用的是这样的:

ProcessStartInfo psi = new ProcessStartInfo("plink.exe", arguments);
psi.RedirectStandardError = true;
psi.RedirectStandardOutput = true;
psi.RedirectStandardInput = true;
psi.UseShellExecute = false;
plink = Process.Start(psi);
StreamWriter input = plink.StandardInput;
StreamReader output = plink.StandardOutput;

input.WriteLine("startCommand"); //Starts the process responsible for logs

input.Write("950"); //It correctly sends the keystrokes

// Some code regarding reading logs from output, some other commands sent to ssh server...

Console.WriteLine("Exiting...");
input.Write('\u001b');  //ESC in UTF16

我认为 SSH.NET 在发送任何其他内容之前会等待最后一个命令结束,但我不知道如何更改它。


我使用 SSH.NET 的尝试:

using (var client = new SshClient(host, user, new PrivateKeyFile(key)))
{
    int timoutCounter = 0;
    do
    {
        timoutCounter++;
        try { client.Connect(); }
        catch (Exception e)
        {
            Console.WriteLine("Connection error: " + e.Message);
        }
    } while (!client.IsConnected);

    ShellStream stream = client.CreateShellStream("shell", 200, 24, 1920, 1080, 4096);

    // it starts the process on remote ssh server that 
    stream.WriteLine("startCommand"); 
    Console.Write("Waiting for any key...");
    Console.ReadKey();

    for (int i = 0; i < 30; i++)
    {
        // Just some quick way for me to know that the device fully loaded
        stream.Expect("LogKeyWord");
    }
    Console.WriteLine("Device started");
    Console.ReadKey();

    // Different ways of entering commands during log output that I've tried

    stream.Write("5"); 
    Console.Write("Waiting for any key...");
    Console.ReadKey();

    stream.WriteLine("6");
    Console.Write("Waiting for any key...");
    Console.ReadKey();

    stream.Write("\u001b"); 
    Console.Write("Waiting for any key...");
    Console.ReadKey();

    var test97 = new StreamWriter(stream);
    test97.Write("7");
    Console.Write("Waiting for any key...");
    Console.ReadKey();

    test97.WriteLine("8");
    Console.Write("Waiting for any key...");
    Console.ReadKey();

    client.RunCommand("11");
    Console.Write("Waiting for any key...");
    Console.ReadKey();

    var test = client.CreateCommand("31");
    test.Execute();
    Console.Write("Waiting for any key...");
    Console.ReadKey();

    client.Disconnect();
}

【问题讨论】:

  • 我知道这只是一个愚蠢的猜测,但您是否需要在命令末尾发送类似\r\n 的内容?如果您检查从 putty 检索到的数据(我这样做了),它会自动附加这些字节(这在您按键盘上的 Enter 时很有意义)。
  • 我现在没有工作实验室来测试它。但是我不想发送输入,因为它是其他一些命令。发送一个数字/ESC 符号是我想要实现的。最后,我刚刚使用 plink 完成了这项工作。

标签: c# ssh putty plink ssh.net


【解决方案1】:

只是猜测,但我会尝试刷新流。

更新:

写了一个小实验,我无法重现这个问题。看这里:https://github.com/scottstephens-repros/SSHNetInterleavedIORepro

因此,这可能是特定于您的代码、您尝试远程运行的程序或远程机器的操作系统、sshd 或配置的问题。我的远程测试机器是 CentOS 7.8,带有 OpenSSH 7.4p1。

【讨论】:

  • 据我所见,ShellStream 的 .WriteLine 自动刷新
  • @blenderfreaky 看看我的非复制版,可能需要您的代码和/或有关远程平台的信息以及您尝试运行的进程来确定您的问题是什么。
  • 嗯。你的 non-repro 似乎在我这边也能正常工作,用 \u001b 发送 Escape 似乎也能正常工作。 (OpenSSH_for_Windows_7.7p1,LibreSSL 2.6.5)。猜猜我的代码还有其他问题。
猜你喜欢
  • 1970-01-01
  • 2015-10-13
  • 1970-01-01
  • 1970-01-01
  • 2012-05-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-27
相关资源
最近更新 更多