I have 2 problems with using SSH.NET library.
I would like to create SSH connection and then disconnect. But if I start asynchronous read, disconnecting causes problems. My program simply freezes when I try to end a connection.
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
}
I also do not know how to create a connection that will be availbe from anywhere in the code. I would like to be able to define IP, UserName and Password (eg write them in some textBoxes), establish a connection and then interact with it by executing some commands and getting input. Passing the credentials, as I understand, requires some event hanlder (eg button1_Click), but then if I would like to interact with the created stream = ssh.CreateShellStream(...)
by passing commands with eg button2_Click, I cannot do that because "The name "stream" does not exist in the current context".
Earlier I have been doing it by plik (from PuTTY) and Process functionality of C#:
private void ConnectButton_Click(object sender, EventArgs e)
{
...
p = new Process();
...
sw = p.StandardInput;
...
}
where sw is a streamwriter defined outside of the ConnectButton_Click event handler.
Thanks.
This is a deadlock. button1_Click
is running on your UI thread, as is the Invoke
inside of DataReceived
.
SSH.NET does not internally use async -- all of it's "async" methods simply wrap a sync method in a thread pool and lock.
The flow will be this:
BeginRead
grabs hold of the lock and starts reading. Disconnect
waits on the lock, in the UI thread, until `BeginRead is done with it. BeginRead
finishes the read, and calls DataReceived
which calls Invoke
while still holding the lock. Invoke
waits for the UI thread to process its message -- but it never will, because the UI thread is waiting on Disconnect
. BeginRead
and Disconnect
are both waiting for each-other to finish -- a deadlock. A quick way to test this would be to change the Invoke
call to BeginInvoke
, which will remove the deadlock.
As far as accessing these objects from anywhere in your Form
, just make them members of the class.
I also stumbled accross this problem and the way I see it there is no way getting around this without modifying SSH.NET code. There is following block of code in SSH.NET, (Session.cs:584):
ExecuteThread(() =>
{
try
{
MessageListener();
}
finally
{
_messageListenerCompleted.Set();
}
});
This leads to following block of code(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();
inside disconnect it waits for _messageListenerCompleted.WaitOne() But this can never happen because _messageListenerCompleted.Set() is called in try{}finally{} block. So to solve this we should either call: _messageListenerCompleted.Set() before calling disconnect() during socket exception or handling Dissconnect somewhere outside
SocketRead(int length, ref byte[] buffer)
function.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.