Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Automatically resume SFTP download after network connection is restored with SSH.NET

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.

like image 672
Rishanthakumar Avatar asked May 23 '17 15:05

Rishanthakumar


People also ask

How do I resume a SFTP transfer?

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.

Does .NET support SFTP?

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.


1 Answers

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)

like image 139
Martin Prikryl Avatar answered Sep 22 '22 20:09

Martin Prikryl