【问题标题】:Using a SSH library to connect to unix and tail a file: Is this the right approach?使用 SSH 库连接到 unix 并跟踪文件:这是正确的方法吗?
【发布时间】:2011-09-26 06:22:58
【问题描述】:

正如我在其他几个问题中所述,我一直在使用new SSH .NET library 连接到 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) 之间的任何数据。

现在我不确定 2 件事,首先是我感觉每次都可能会因为整个 MemoryStream 位置的变化而错过一些数据(由于我缺乏对 MemoryStreams 的经验,其次是整个睡眠 1 秒钟,然后再次更新,这件事似乎很陈旧而且效率低下......有什么想法吗?

【问题讨论】:

    标签: c# multithreading unix .net-4.0 ssh


    【解决方案1】:

    嗯,我刚刚意识到您不是 SSH 库的创建者(尽管它在 codeplex 上,因此您可以提交补丁):您可能希望将循环包装到 try {} finally {} 中并调用 shell.Stop() finally 块以确保它始终被清理。

    根据可用的接口,轮询可能是唯一的方法,它本身并不是坏事。您是否丢失数据取决于shell 对象为缓冲所做的工作:它是否缓冲内存中的所有输出,是否会在一段时间后丢弃一些输出?

    我原来的观点仍然成立:

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

    另外:我会考虑制作 shell 对象(无论CreateShell 返回什么类型)IDisposable。从您的描述看来,shell.Stop() 需要进行清理,以防在 while 循环中引发一些异常。

    【讨论】:

    • 这个库有一个它使用的自定义内存流,称为 PipeStream,创建者让它听起来就像你描述的 BlockingQueue,如果你有机会,请检查一下:sshnet.codeplex.com/discussions/263452
    • @Hershizer33, PipeStream 看起来就是你想要的。虽然ReadAvailable 的实现看起来有点奇怪:它总是要求缓冲区至少有count 字节来读取或刷新。
    • 使用 PipeStream 带来了一些问题...似乎在其代码的 Read 函数中永远循环,我能想到的唯一原因是,由于日志文件的流式传输速度如此之快,它总是有要读取的数据,并继续阅读……有什么想法吗?
    • 尝试不使用StreamReader,直接使用Read thestream 方法,看看你会得到什么。
    • 这似乎行得通,只是担心现在可能会丢失数据......我的循环内部现在看起来像这样:byte[] tempBytes = new byte[output.Length]; output.Read(tempBytes, 0, tempBytes.Length); System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding(); string result = enc.GetString(tempBytes); UpdateAP2TextBox(result); Thread.Sleep(1000); 我想因为这应该删除它读取的内容,没关系始终从 0 开始阅读到 Length
    猜你喜欢
    • 2011-10-07
    • 1970-01-01
    • 1970-01-01
    • 2011-10-22
    • 1970-01-01
    • 1970-01-01
    • 2012-11-08
    • 1970-01-01
    • 2015-03-17
    相关资源
    最近更新 更多