I'm having trouble with using SftpClient. First, I'm inexplicably hitting SshException: Channel was closed. Second, when I detect that I hit it, I can't reconnect even if I create a new SftpClient object.
I upload for ~10 minutes on 4 different threads and for some reason I always hit a Channel was closed exception. To try and mitigate this I wrote some code to watch for this exception and attempt to throw away my sftpclient object and reconnect. However when I call .Connect(), I STILL get "Channel was closed" even after disposing and nulling my SftpClient object. Clearly I'm doing something wrong. Any ideas?
```
Code for sftpclient management: one per thread
protected SftpClient Client
{
get
{
SftpClient client;
if (!this.clients.TryGetValue(Thread.CurrentThread, out client))
{
client = new SftpClient(this.host, SftpUserName, this.privateKeyFile);
this.clients[Thread.CurrentThread] = client;
}
// For now only do one of these at a time
lock (this.connectionLock)
{
if (!client.IsConnected)
{
this.LogContext.LogInfo("Connecting client for thread " + Thread.CurrentThread.ManagedThreadId);
client.Connect();
}
}
return client;
}
}
// Detect and attempt to refresh connection
protected void RefreshConnectionOnSshException(Action action)
{
int retryLimit = 2;
for (int retries = 0; retries <= retryLimit; retries++)
{
try
{
action();
break;
}
catch (SshException err)
{
if (retries < retryLimit)
{
this.LogContext.LogWarning("SshException was thrown. Disposing the SftpClient and letting a new one be created: " + err.Message);
this.clients[Thread.CurrentThread].Dispose();
this.clients.Remove(Thread.CurrentThread);
Thread.Sleep(BaseManager.RetryIntervalMilliseconds);
}
else
{
throw;
}
}
}
}
// Sample copy instruction
protected override void InternalPerformCopyInstruction(CopyInstruction instruction)
{
var fi = new FileInfo(instruction.SourceFileName);
using (Stream file = fi.OpenRead())
{
string destination = this.CleanRemotePath(instruction.DestFileName);
if (this.FileExists(destination))
{
this.LogContext.LogInfo("Destination already exists. Deleting before upload: " + destination);
this.RefreshConnectionOnSshException(() => this.Client.DeleteFile(destination));
}
this.LogContext.LogInfo("Securely uploading file: " + destination);
this.RefreshConnectionOnSshException(() => this.Client.UploadFile(file, destination));
this.LogContext.LogInfo("Completed uploading file: " + destination);
}
}
```
Then I hit an error that looks like this:
2014-10-07T03:16:11.951Z,,6504,,,,,,,,2db96b5f682f4060b5ff731e6b89aee3,041e76d3f0534333a84800a677aca014,DoPublish,Warning,SshException was thrown. Disposing the SftpClient and letting a new one be created: Channel was closed.
2014-10-07T03:16:15.073Z,,6504,,,,,,,,2db96b5f682f4060b5ff731e6b89aee3,041e76d3f0534333a84800a677aca014,DoPublish,Information,Connecting client for thread
2014-10-07T03:16:15.681Z,,6504,,,,,,,,2db96b5f682f4060b5ff731e6b89aee3,041e76d3f0534333a84800a677aca014,DoPublish,Warning,SshException was thrown. Disposing the SftpClient and letting a new one be created: Channel was closed.
2014-10-07T03:16:18.802Z,,6504,,,,,,,,2db96b5f682f4060b5ff731e6b89aee3,041e76d3f0534333a84800a677aca014,DoPublish,Information,Connecting client for thread
2014-10-07T03:16:19.394Z,,6504,,,,,,,,2db96b5f682f4060b5ff731e6b89aee3,041e76d3f0534333a84800a677aca014,DoPublish,Error,"Exception has occurred:Renci.SshNet.Common.SshException: Channel was closed. at Renci.SshNet.Sftp.SubsystemSession.WaitOnHandle(WaitHandle waitHandle, TimeSpan operationTimeout) at __Renci.SshNet.Sftp.SftpSession.OnChannelOpen()__ at Applications..SftpCopy.get_Client() in .\SftpCopy.cs:line 98
Comments: ** Comment from web user: drieseng **
I upload for ~10 minutes on 4 different threads and for some reason I always hit a Channel was closed exception. To try and mitigate this I wrote some code to watch for this exception and attempt to throw away my sftpclient object and reconnect. However when I call .Connect(), I STILL get "Channel was closed" even after disposing and nulling my SftpClient object. Clearly I'm doing something wrong. Any ideas?
```
Code for sftpclient management: one per thread
protected SftpClient Client
{
get
{
SftpClient client;
if (!this.clients.TryGetValue(Thread.CurrentThread, out client))
{
client = new SftpClient(this.host, SftpUserName, this.privateKeyFile);
this.clients[Thread.CurrentThread] = client;
}
// For now only do one of these at a time
lock (this.connectionLock)
{
if (!client.IsConnected)
{
this.LogContext.LogInfo("Connecting client for thread " + Thread.CurrentThread.ManagedThreadId);
client.Connect();
}
}
return client;
}
}
// Detect and attempt to refresh connection
protected void RefreshConnectionOnSshException(Action action)
{
int retryLimit = 2;
for (int retries = 0; retries <= retryLimit; retries++)
{
try
{
action();
break;
}
catch (SshException err)
{
if (retries < retryLimit)
{
this.LogContext.LogWarning("SshException was thrown. Disposing the SftpClient and letting a new one be created: " + err.Message);
this.clients[Thread.CurrentThread].Dispose();
this.clients.Remove(Thread.CurrentThread);
Thread.Sleep(BaseManager.RetryIntervalMilliseconds);
}
else
{
throw;
}
}
}
}
// Sample copy instruction
protected override void InternalPerformCopyInstruction(CopyInstruction instruction)
{
var fi = new FileInfo(instruction.SourceFileName);
using (Stream file = fi.OpenRead())
{
string destination = this.CleanRemotePath(instruction.DestFileName);
if (this.FileExists(destination))
{
this.LogContext.LogInfo("Destination already exists. Deleting before upload: " + destination);
this.RefreshConnectionOnSshException(() => this.Client.DeleteFile(destination));
}
this.LogContext.LogInfo("Securely uploading file: " + destination);
this.RefreshConnectionOnSshException(() => this.Client.UploadFile(file, destination));
this.LogContext.LogInfo("Completed uploading file: " + destination);
}
}
```
Then I hit an error that looks like this:
2014-10-07T03:16:11.951Z,,6504,,,,,,,,2db96b5f682f4060b5ff731e6b89aee3,041e76d3f0534333a84800a677aca014,DoPublish,Warning,SshException was thrown. Disposing the SftpClient and letting a new one be created: Channel was closed.
2014-10-07T03:16:15.073Z,,6504,,,,,,,,2db96b5f682f4060b5ff731e6b89aee3,041e76d3f0534333a84800a677aca014,DoPublish,Information,Connecting client for thread
2014-10-07T03:16:15.681Z,,6504,,,,,,,,2db96b5f682f4060b5ff731e6b89aee3,041e76d3f0534333a84800a677aca014,DoPublish,Warning,SshException was thrown. Disposing the SftpClient and letting a new one be created: Channel was closed.
2014-10-07T03:16:18.802Z,,6504,,,,,,,,2db96b5f682f4060b5ff731e6b89aee3,041e76d3f0534333a84800a677aca014,DoPublish,Information,Connecting client for thread
2014-10-07T03:16:19.394Z,,6504,,,,,,,,2db96b5f682f4060b5ff731e6b89aee3,041e76d3f0534333a84800a677aca014,DoPublish,Error,"Exception has occurred:Renci.SshNet.Common.SshException: Channel was closed. at Renci.SshNet.Sftp.SubsystemSession.WaitOnHandle(WaitHandle waitHandle, TimeSpan operationTimeout) at __Renci.SshNet.Sftp.SftpSession.OnChannelOpen()__ at Applications..SftpCopy.get_Client() in .\SftpCopy.cs:line 98
Comments: ** Comment from web user: drieseng **
SftpClient.IsConnected would indeed return true if the SSH session is established, but the channel is closed.
I'll look into this.