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

一个人想着一个人 提交于 2019-12-01 06:47:43

问题


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.


回答1:


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
        {
            Stream destinationStream;
            if (retrying)
            {
                destinationStream = new FileStream(destinationFile, FileMode.Append);
            }
            else
            {
                destinationStream = new FileStream(destinationFile, FileMode.Create);
            }

            using (destinationStream)
            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-dss 2048 0b:77:8b:68:f4:45:b1:3c:87:ad:5c:be:3b:c5:72:78",
    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)



来源:https://stackoverflow.com/questions/44139122/automatically-resume-sftp-download-after-network-connection-is-restored-with-ssh

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!