如何使用 .net ssh sshclient 保持会话
本文关键字:会话 sshclient ssh 何使用 net | 更新日期: 2023-09-27 18:24:45
SshClient client;
var sethost = client.RunCommand("export DOCKER_HOST=:2375");
var infohost = client.RunCommand("docker info");
var ps = client.RunCommand("docker ps");
我正在将上述命令与 .Net 的 ssh 客户端一起使用,但它不会保留在接下来的两个命令中导出的第一个命令的状态。
如果我手动 ssh 并执行 3 个命令,它会按预期工作,但上面的 c# 代码似乎忘记了后续命令中的导出。
我假设您正在使用 SSH.NET 库。在下面的解决方案中,我使用了稳定版本(2013.4.7(,该版本也可作为NuGet包提供。
有两种可能的解决方案可以使其正常工作。第一个方法是将要运行的命令组合到一个 RunCommand 中。每次调用 RunCommand 时都会启动一个新的 shell,并因此忘记您执行的任何环境设置。通过将命令与 && or ||
运算符链接,可以实现所有命令都可以在同一 Shell 中执行。
static void SolutionOne(ConnectionInfo connection)
{
using (SshClient client = new SshClient(connection))
{
client.ErrorOccurred += (e, s) =>
{
Debug.WriteLine(s.Exception);
};
client.Connect();
// each RunCommand starts its own/new Shell...
var sethost = client.RunCommand("export DOCKER_HOST=:2375");
// ... nothing is kept...
var infohost = client.RunCommand("export -p");
if (!infohost.Result.Contains("DOCKER_HOST"))
{
Console.WriteLine("sorry, a new shell was started for this command");
}
// ... across run commands
var ps = client.RunCommand("echo has value: $DOCKER");
Console.WriteLine(ps.Result);
Console.WriteLine("");
Console.WriteLine("Chain the linux commands...");
// chain all commands with &&
var concatAll = client.RunCommand("export DOCKER_HOST=:2375 && export -p | grep DO && echo has value: $DOCKER_HOST");
// you should see DOCKER_HOST on the last line!
Console.WriteLine("> see has value: 2375 at the end?");
Console.WriteLine(concatAll.Result);
}
}
第二种解决方案是从SshClient
获取ShellStream
。这使您有机会读取和写入字节,就像读取文件一样。
建立连接和流后,我们读取要阅读的所有内容。一旦流为空,我们通过写入流来发送第一个命令。然后,我们稍等片刻,让流获取要读取的数据,然后再次继续从流中读取,直到流为空。那时我们可以开始下一个命令,冲洗并重复,直到所有命令都完成。
static void SolutionTwo(ConnectionInfo connection)
{
using (SshClient client = new SshClient(connection))
{
client.ErrorOccurred += (e, s) =>
{
Debug.WriteLine(s.Exception);
};
client.Connect();
using (var stream = client.CreateShellStream("dumb", 512, 96, 800, 600, 8191))
{
stream.ErrorOccurred += (e, s) =>
{
Debug.WriteLine(s.Exception);
};
// read welcome message
Console.WriteLine(ReadFromStream(stream));
// first command and read its output
WriteToStream(stream, "uname'n");
Console.WriteLine(ReadFromStream(stream));
// second and output
WriteToStream(stream, "df'n");
Console.WriteLine(ReadFromStream(stream));
// third and output
WriteToStream(stream, "ps aux'n");
Console.WriteLine(ReadFromStream(stream));
}
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine(" >>>>>we are all done");
Console.ForegroundColor = ConsoleColor.White;
}
}
static void WriteToStream(ShellStream stream, string command)
{
stream.Write(command);
}
static StringBuilder ReadFromStream(ShellStream stream)
{
var result = new StringBuilder();
// there seems to be a timing/concurrency issue
// which I only could fix with using this
// useless Sleep calls
Thread.Sleep(500);
// wait for the Stream to have data
while (stream.Length == 0)
{
// yes, I know ...
Thread.Sleep(500);
}
// let's read!
string line;
while ((line = stream.ReadLine()) != null)
{
result.AppendLine(line);
}
return result;
}
正如您在ReadFromStream
方法中注意到的那样,有一些可疑的黑客攻击。我很难从流中阅读可靠的内容。在我最初的尝试中,我使用了 DataReceived
事件,但无论我如何尝试,它要么适用于几行甚至字符,要么根本不起作用。最后,我又回到了一个讨厌的Thread.Sleep电话,该电话一直工作可靠。也许是库中的错误或本地设置中的某些错误,但我放弃了。