使用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,UserName和Password(例如,在一些textBox中写入它们),建立连接,然后通过执行一些命令和获取输入与它进行交互。根据我的理解,传递凭证需要一些事件处理器(例如button1_Click),但是如果我想通过传递命令来与创建的stream = ssh.CreateShellStream(...)
进行交互。 button2_Click,我不能这样做,因为“名称”流“在当前上下文中不存在”。
早些时候我一直在使用plik(来自PuTTY)和C#的进程功能:
private void ConnectButton_Click(object sender, EventArgs e)
{
...
p = new Process();
...
sw = p.StandardInput;
...
}
其中sw是在ConnectButton_Click事件处理程序之外定义的streamwriter。
感谢。
答案 0 :(得分:3)
这是一个僵局。 button1_Click
正在您的UI线程上运行,Invoke
内的DataReceived
也是如此。
SSH.NET内部不使用异步 - 所有这些“异步”方法都只是将一个同步方法包装在一个线程池中并锁定。
流程将是:
BeginRead
抓住锁并开始阅读。Disconnect
等待UI线程中的锁,直到`BeginRead完成。BeginRead
完成了阅读,并在仍然保持锁定时调用DataReceived
来调用Invoke
。Invoke
等待UI线程处理其消息 - 但它永远不会,因为UI线程正在等待Disconnect
。BeginRead
和Disconnect
都在等待彼此完成 - 一个死锁。快速测试方法是将Invoke
调用更改为BeginInvoke
,这将消除死锁。
至于从Form
中的任何位置访问这些对象,只需让它们成为该类的成员。
答案 1 :(得分: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();
内部断开连接等待 _messageListenerCompleted.WaitOne() 但这绝不会发生,因为在 try {} finally {} 块中调用 _messageListenerCompleted.Set()。 所以要解决这个问题,我们应该致电: __ssageListenerCompleted.Set()在套接字异常或处理外的某个地方调用disconnect()之前
SocketRead(int length, ref byte[] buffer)
功能