使用SSH库连接到unix并跟踪文件:这是正确的方法吗

本文关键字:方法 文件 连接 SSH unix 跟踪 使用 | 更新日期: 2023-09-27 18:00:43

正如我在其他几个问题中所说的,我一直在使用一个新的SSH.NET库来连接到Unix服务器并运行各种脚本和命令。好吧,我终于尝试使用它在实时日志文件上运行Unix tail-f,并在Winforms RichTextBox中显示尾部。

由于图书馆还没有完全充实,我想到的唯一一种解决方案似乎缺乏。。。就像你知道必须有更好的方法时的感觉。我在一个单独的线程中有连接/尾随代码,以避免UI线程锁定。这个线程支持取消请求(这将允许连接正常退出,这是确保进程Unix端被终止的唯一方法)。以下是我迄今为止的代码(记录在案,它似乎有效,我只是想思考一下这是否是正确的方法):

PasswordConnectionInfo connectionInfo = new PasswordConnectionInfo(lineIP, userName, password);
string command = "cd /logs; tail -f " + BuildFileName() + " 'r'n";
using (var ssh = new SshClient(connectionInfo))
{
    ssh.Connect();
    var output = new MemoryStream();
    var shell = ssh.CreateShell(Encoding.ASCII, command, output, output);
    shell.Start();
    long positionLastWrite = 0;
    while (!TestBackgroundWorker.CancellationPending) //checks for cancel request  
    {
        output.Position = positionLastWrite;
        var result = new StreamReader(output, Encoding.ASCII).ReadToEnd();
        positionLastWrite = output.Position;
        UpdateTextBox(result);
        Thread.Sleep(1000);
    }
    shell.Stop();
    e.Cancel = true;
}

UpdateTextBox()函数是一种线程安全的更新RichTextBox的方法,用于显示不同线程的尾部。positionLastWrite的东西是为了确保我不会在Thread.Sleep(1000).之间丢失任何数据

现在我不确定有两件事,第一件事是我觉得我可能每次都会因为整个MemoryStream位置的变化而错过一些数据(由于我缺乏MemoryStream的经验),第二件事是整个睡眠1秒然后再次更新的事情似乎很过时,效率很低…有什么想法吗?

使用SSH库连接到unix并跟踪文件:这是正确的方法吗

Mh,我刚刚意识到你不是SSH库的创建者(尽管它在codeplex上,所以你可以提交补丁):你可能想把你的循环包装成try {} finally {},并在finally块中调用shell.Stop(),以确保它总是被清理掉。

根据可用接口的不同,轮询可能是唯一的方法,而且它本身并不坏。是否释放数据取决于shell对象对缓冲的作用:它是否缓冲内存中的所有输出,是否在一定时间后丢弃一些输出?

我最初的观点仍然有效:

想到的一件事是,看起来shell对象一直在内存中缓冲整个输出,这会带来潜在的资源问题(内存不足)。更改接口的一个选项是在shell对象中使用类似BlockingQueue的东西。然后,shell将来自远程主机的输出排入队列,在您的客户端中,您可以坐在那里并退出队列,如果没有可读取的内容,队列将被阻塞。

另外:我会考虑将shell对象(无论CreateShell返回什么类型)设置为IDisposable。根据您的描述,似乎需要shell.Stop()进行清理,这在while循环中抛出异常的情况下不会发生。