使用 SSH.NET 恢复网络连接后自动恢复 SFTP 下载

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

我正在使用 SSH.NET 库来创建 SFTP 客户端。如果网络连接在此超时内再次可用,我需要恢复下载。我正在使用下面提到的方法,如许多示例所示。

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();
    }
}

我正在拔网线以中断下载并测试超时情况。虽然我在超时内再次启用互联网连接以恢复下载,但它没有恢复。我在这里做错了什么?请指教

如果您希望 SSH.NET 在 SftpClient.DownloadFile 内重新连接,则不会。

您必须自己实现重新连接和传输恢复。

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);

或者使用另一个原生支持简历的 SFTP 库。

例如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 喜欢上面那个给你的。

(我是WinSCP的作者)