You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Renci.SshNet断开SshClient时触发System.ObjectDisposedException异常

问题描述

使用Renci.SshNet执行SSH命令的代码如下:

public int ExecuteShellCommand(string a_command, bool log = false)
{
    int res = 0;
    try
    {
        using (var sshclient = new SshClient(m_connNfo))
        {
            sshclient.Connect();

            using (var cmd = sshclient.CreateCommand(a_command + " >&2"))
            {
                var resultExe = cmd.Execute();
                if (log)
                {
                    Console.Write(resultExe);
                    var extended = cmd.ExtendedOutputStream;
                    var reader = new StreamReader(extended);
                    Console.Write(reader.ReadToEnd());
                }
                res = cmd.ExitStatus;
            }
        }
    }
    catch (Exception)
    {
        return -1;
    }
    return res;
}

其中连接信息m_connNfo的创建代码:

m_connNfo = new ConnectionInfo(ConfigurationManager.AppSettings[IP], 22, User,
       new AuthenticationMethod[]{
            // Pasword based Authentication
            new PasswordAuthenticationMethod(User,ApiInstance.GetPass())
             });

该方法可正常执行并实现预期功能,但在try块结束(using块释放SshClient)时,或提前调用sshclient.Disconnect();后,终端会抛出System.ObjectDisposedException in System.dll异常,需分析异常产生原因。

异常原因分析
  • 流资源未正确释放:读取ExtendedOutputStream时创建的StreamReader未用using包裹,导致该对象持续持有对输出流的引用。当SshClient释放底层连接时,会尝试关闭所有关联流,此时StreamReader仍引用已被释放的流对象,触发ObjectDisposedException。
  • 命令重定向引发流处理冲突:命令后追加的>&2将标准输出重定向到标准错误流,即便代码读取了两个流,仍可能存在流数据未完全读取的情况。SshClient释放时会清理未处理完的流资源,此时访问已处于释放状态的流会引发异常。
  • 资源释放顺序的潜在冲突:虽然using块会按顺序释放Command和SshClient,但如果Command的流资源未完全清理完成,SshClient关闭连接时会强制终止相关流操作,导致访问已释放对象的异常。
解决建议
  1. 给StreamReader添加using块,确保流资源被正确释放:
if (log)
{
    Console.Write(resultExe);
    using (var reader = new StreamReader(cmd.ExtendedOutputStream))
    {
        Console.Write(reader.ReadToEnd());
    }
}
  1. 移除命令中的>&2重定向,分别读取标准输出和标准错误流,避免流混淆:
using (var cmd = sshclient.CreateCommand(a_command))
{
    var resultExe = cmd.Execute();
    if (log)
    {
        Console.Write(resultExe);
        using (var reader = new StreamReader(cmd.ExtendedOutputStream))
        {
            Console.Write(reader.ReadToEnd());
        }
    }
    res = cmd.ExitStatus;
}
  1. 在释放Command前,确保所有流操作完成,可手动调用cmd.Dispose()确保资源清理完毕。

内容的提问来源于stack exchange,提问作者Alex

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 20:57:22