I am using SSH.NET library to create SFTP client. I need to resume the download, if network connection becomes available again within this timeout. I am using the below mentioned approach as shown in many examples.
PrivateKeyFile ObjPrivateKey = new PrivateKeyFile(keyStream);
PrivateKeyAuthenticationMethod ObjPrivateKeyAutentication = new PrivateKeyAuthenticationMethod(username, ObjPrivateKey);
var connectionInfo = new ConnectionInfo(hostAddress, port, username, ObjPrivateKeyAutentication);
try
{
using (var client = new SftpClient(connectionInfo))
{
client.ConnectionInfo.Timeout = TimeSpan.FromSeconds(10);
client.Connect();
if (!client.IsConnected)
{
return false;
}
if (!client.Exists(source))
{
return false;
}
var fileName = Path.GetFileName(source);
using (var fs = new FileStream(destination + fileName, FileMode.Create))
{
client.DownloadFile(source, fs, printActionDel);
fs.Close();
returnState = true;
}
client.Disconnect();
client.Dispose();
}
}
I am unplugging the network cable to interrupt the download and test the timeout scenario. Though I enable the internet connection again within the timeout to resume the download, it is not resuming. What am I doing wrong here? Please advice.
The SFTP protocol supports both `reget` and `reput` commands which allow you to resume downloads and uploads respectively. Like FTP, these commands simply restart the upload from where it left off. When unexpected interruptions occur, FTP resume is there to pick up where your file transfer left off.
More .NET componentsProvides secure remote file system access over an SSH channel using the SFTP protocol. Makes it easy to transfer files between your application and Unix/Windows SSH servers.
If you expect the SSH.NET to reconnect within SftpClient.DownloadFile
, it won't.
You have to implement the re-connect and transfer resume on your own.
PrivateKeyFile ObjPrivateKey = new PrivateKeyFile(keyStream);
PrivateKeyAuthenticationMethod ObjPrivateKeyAutentication =
new PrivateKeyAuthenticationMethod(username, ObjPrivateKey);
var connectionInfo =
new ConnectionInfo(hostAddress, port, username, ObjPrivateKeyAutentication);
bool retry = false;
do
{
bool retrying = retry;
retry = false;
using (var client = new SftpClient(connectionInfo))
{
client.Connect();
if (!client.Exists(source))
{
return false;
}
var fileName = Path.GetFileName(source);
var destinationFile = Path.Combine(destination, fileName);
try
{
var mode = retrying ? FileMode.Append : FileMode.Create;
using (var destinationStream = new FileStream(destinationFile, mode))
using (var sourceStream = client.Open(source, FileMode.Open))
{
sourceStream.Seek(destinationStream.Length, SeekOrigin.Begin);
// You can simply use sourceStream.CopyTo(destinationStream) here.
// But if you need to monitor download progress,
// you have to loop yourself.
byte[] buffer = new byte[81920];
int read;
ulong total = (ulong)destinationStream.Length;
while ((read = sourceStream.Read(buffer, 0, buffer.Length)) != 0)
{
destinationStream.Write(buffer, 0, read);
total = total + (ulong)read;
// report progress
printActionDel(total);
}
}
}
catch (SshException e)
{
retry = true;
}
}
}
while (retry);
Or use another SFTP library that supports the resume natively.
For example WinSCP .NET assembly does resume automatically in its Session.GetFiles
method.
SessionOptions sessionOptions = new SessionOptions
{
Protocol = Protocol.Sftp,
HostName = hostAddress,
PortNumber = port,
UserName = username,
SshHostKeyFingerprint = "ssh-rsa 2048 xxxxxxxxxxx...=",
SshPrivateKeyPath = keyPath
};
using (Session session = new Session())
{
session.FileTransferProgress += session_FileTransferProgress;
session.Open(sessionOptions);
var fileName = Path.GetFileName(source);
var destinationFile = Path.Combine(destination, fileName);
session.GetFiles(source, destinationFile).Check();
}
WinSCP GUI can generate an SFTP download code template like the one above for you.
(I'm the author of WinSCP)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With