使用 SSH.NET 在命令输出期间发送输入 [英] Sending input during command output with SSH.NET

查看:92
本文介绍了使用 SSH.NET 在命令输出期间发送输入的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

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

我尝试使用 CreateShellStream 的方法:

  • shellStream.WriteLine('ascii 中的按键或字符串')
  • 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 输入 = plink.StandardInput;StreamReader 输出 = plink.StandardOutput;input.WriteLine("startCommand");//启动负责日志的进程input.Write("950");//它正确发送击键//一些关于从输出中读取日志的代码,一些发送到 ssh 服务器的其他命令...Console.WriteLine("退出中...");input.Write('\u001b');//ESC UTF16

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

<小时>

我尝试使用 SSH.NET:

using (var client = new SshClient(host, user, new PrivateKeyFile(key))){int timoutCounter = 0;做{超时计数器++;试试 { client.Connect();}捕获(例外 e){Console.WriteLine("连接错误:" + e.Message);}} while (!client.IsConnected);ShellStream stream = client.CreateShellStream("shell", 200, 24, 1920, 1080, 4096);//它在远程 ssh 服务器上启动进程stream.WriteLine("startCommand");Console.Write("正在等待任何键...");Console.ReadKey();for (int i = 0; i <30; i++){//只是让我知道设备已完全加载的一些快速方法stream.Expect("LogKeyWord");}Console.WriteLine("设备启动");Console.ReadKey();//我尝试过的在日志输出期间输入命令的不同方式stream.Write("5");Console.Write("正在等待任何键...");Console.ReadKey();stream.WriteLine("6");Console.Write("正在等待任何键...");Console.ReadKey();stream.Write("\u001b");Console.Write("正在等待任何键...");Console.ReadKey();var test97 = new StreamWriter(stream);test97.Write("7");Console.Write("正在等待任何键...");Console.ReadKey();test97.WriteLine("8");Console.Write("正在等待任何键...");Console.ReadKey();client.RunCommand("11");Console.Write("正在等待任何键...");Console.ReadKey();var test = client.CreateCommand("31");测试执行();Console.Write("正在等待任何键...");Console.ReadKey();客户端断开连接();}

解决方案

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

更新:

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

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

With PuTTY, I connect to an SSH server and then I execute a command that constantly output logs (multiple lines per second). During this process I can send some keystrokes which are commands, ie. putting 123 or Esc which stops the process. If I put a valid keystroke I can see it on output device, so I always know if keystroke was sent or not.

I want to do it programmatically - connect to the SSH server, execute the main command and then send it some key strokes as commands while in the same time monitoring the logs where I can see the response to my commands.

So I want to do it with SSH.NET - it's a neat SSH tool, it outputs reliably and it's nice to work with. However I have a problem - I can connect to this server, execute a command, but while it dumps the log I cannot send it any key stroke.

Ways I've tried using CreateShellStream:

  • shellStream.WriteLine('keystroke in ascii or just string')
  • sshClient.CreateCommand('keystroke in ascii or just string') and then sshClient.Execute();
  • using StreamWriter(shellstream) and writing to it

I've tried ascii codes, UTF-16 codes, strings, nothing works unfortunately.

The same thing done with Plink (PuTTY command-line tool) works just fine, but it's much messier and I would prefer to use SSH.NET. Do you know what is the difference between sending keystrokes with SSH.NET and Plink? Why does it work flawlessly with Plink? I've tried debugging it with Wireshark, unfortunately SSH makes it really difficult to do so.

With Plink I'm using basically something like this:

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

I think that SSH.NET waits for the last command to end before sending anything else but I don't know how to change it.


My tries using 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();
}

解决方案

Just a guess, but I would try flushing the stream.

Update:

Wrote a little experiment and I can't reproduce the problem. Take a look here: https://github.com/scottstephens-repros/SSHNetInterleavedIORepro

So this is probably an issue specific to your code, the program you're trying to run remotely, or the remote machine's OS, sshd, or configuration. My remote test machine was CentOS 7.8, with OpenSSH 7.4p1.

这篇关于使用 SSH.NET 在命令输出期间发送输入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆