SSH.NET Library - SshClient.Dispose(),公共连接

本文关键字:连接 Dispose NET Library SshClient SSH | 更新日期: 2023-09-27 18:17:25

我在使用 SSH.NET 库时遇到 2 个问题。

我想创建SSH连接,然后断开连接。但是,如果我开始异步读取,断开连接会导致问题。当我尝试结束连接时,我的程序只是冻结。

public void button1_Click(object sender, EventArgs e)
{
    var ssh = new SshClient(IP, UserName, Password);
    ssh.Connect();
    var stream = ssh.CreateShellStream("anything", 80, 24, 800, 600, 4096);
    byte[] buffer = new byte[1000];
    stream.BeginRead(buffer, 0, buffer.Length, null, null);
    stream.DataReceived += new EventHandler<Renci.SshNet.Common.ShellDataEventArgs>(
        (s, ex) =>
        {
            Invoke((MethodInvoker)delegate
            {
                textBox1.AppendText(stream.Read());
            });
        }
    );
    stream.WriteLine("ls");
    stream.Dispose();
    ssh.Disconnect(); //problem here
}

我也不知道如何创建一个可以从代码中的任何位置使用的连接。我希望能够定义IP,用户名和密码(例如将它们写入某些文本框中(,建立连接,然后通过执行一些命令和获取输入来与之交互。据我了解,传递凭据需要一些事件 hanlder(例如 button1_Click(,但是如果我想通过传递带有 button2_Click 的命令来与创建的stream = ssh.CreateShellStream(...)进行交互,我不能这样做,因为"名称"流"在当前上下文中不存在"。

早些时候我一直在通过 plik(来自 PuTTY(和 C# 的流程功能来做到这一点:

private void ConnectButton_Click(object sender, EventArgs e)
{
    ...
    p = new Process();
    ...
    sw = p.StandardInput;
    ...
}

其中 sw 是在 ConnectButton_Click 事件处理程序之外定义的流编写器。

谢谢。

SSH.NET Library - SshClient.Dispose(),公共连接

这是一个

死锁。 button1_Click 在您的 UI 线程上运行,DataReceived 内部的Invoke也是如此。

SSH.NET 内部不使用异步 - 它所有的"异步"方法都只是将同步方法包装在线程池中并锁定。

流程将是这样的:

  1. BeginRead抓住锁,开始阅读。
  2. Disconnect在 UI 线程中等待锁,直到"开始阅读"完成。
  3. BeginRead完成读取,并调用DataReceivedInvoke同时仍按住锁。
  4. Invoke等待 UI 线程处理其消息 - 但它永远不会,因为 UI 线程正在等待Disconnect
  5. 现在BeginReadDisconnect都在等待对方的结束——一个僵局。

测试这一点的一种快速方法是将Invoke调用更改为 BeginInvoke ,这将消除死锁。

至于从Form中的任何位置访问这些对象,只需使它们成为类的成员即可。

我也偶然发现了这个问题,在我看来,如果不修改 SSH.NET 代码就无法解决这个问题。SSH.NET 中有以下代码块(会话.cs:584(:

ExecuteThread(() =>
                    {
                        try
                        {
                            MessageListener();
                        }
                        finally
                        {
                            _messageListenerCompleted.Set();
                        }
                    });

这会导致以下代码块(Session.NET.cs:220(:

partial void SocketRead(int length, ref byte[] buffer)
..
catch (SocketException exp) {
if (exp.SocketErrorCode == SocketError.ConnectionAborted)    
{
      buffer = new byte[length];
      Disconnect();

内部断开连接它等待_messageListenerCompleted.WaitOne((但这永远不会发生,因为 try{}finally {} 块中调用了 _messageListenerCompleted.Set((。因此,要解决此问题,我们应该调用:_messageListenerCompleted.Set(( 在套接字异常期间调用 disconnect(( 或处理外部某处断开连接之前

  SocketRead(int length, ref byte[] buffer)

功能。