1

我在使用 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、用户名和密码(例如将它们写在一些文本框中),建立连接,然后通过执行一些命令和获取输入来与之交互。据我了解,传递凭据需要一些事件处理程序(例如 button1_Click),但是如果我想与stream = ssh.CreateShellStream(...)通过传递命令创建的交互,例如 button2_Click,我不能这样做,因为“名称”流“不存在于当前上下文”。

早些时候,我一直通过 plik(来自 PuTTY)和 C# 的 Process 功能来做这件事:

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

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

谢谢。

4

2 回答 2

3

这是一个僵局。button1_Click正在您的 UI 线程上运行InvokeDataReceived.

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

流程将是这样的:

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

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

至于从你的任何地方访问这些对象Form,只需让它们成为类的成员。

于 2014-08-10T15:58:57.853 回答
1

我也偶然发现了这个问题,我认为如果不修改 SSH.NET 代码就无法解决这个问题。SSH.NET 中有以下代码块(Session.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();

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

  SocketRead(int length, ref byte[] buffer)

功能。

于 2015-12-23T09:17:28.670 回答