C# SFTP客户端实现文件传输

一、SFTP信息

SSH:加密的远程登陆/命令通道协议,可以链接到另一台机器执行命令,也可以传输一些文件;

SFTP:跑在SSH上面的文件传输协议,端口为22;

FTP:1971年的明文传输协议,端口21,与SFTP没有关系;

二、服务端OpenSSH

  1. systemctl enable --now ssh:开机自启 + 立即启动,启动的服务名为ssh.service

  2. /etc/init.d/sshd start:运行sshd脚本,start为参数,还有stop啥的

  3. ssh-keygen -A:生成密钥ssh_host_*_key,在服务端与客户端进行连接时,客户端发给服务端由它生成的公钥,服务端会留存这个公钥以识别OpenSSH

  4. /etc/ssh/sshd_config为SSH的配置文件,里面有端口、登陆账号(即Linux账号)、密钥等;

三、客户端

  1. 加载远程文件\目录列表

    SftpClient client = new SftpClient(ip, port, userName, password); // 除了port为int外,其他参数都是string,用户名和密码是Linux允许访问OpenSSH账号名和密码,sshd_config AllowUser那里做配置的
    client.Connect();
    List entries = client.ListDirectory(path) // path服务端的路径
    .Where(t => t.Name != "." && t.Name != ".." && !t.Name.StartsWith('.')) // 剔除"."当前目录、".."上级目录、"."开头的配置文件
    .OrderByDescending(t => t.IsDirectory)
    .ThenBy(t => t.Name, StringComparer.OrdinalIgnoreCase)
    .Select(t => mew TransFileInfo()
    {
    Name = t.Name,
    Size = t.IsDirectory ? 0 : t.Length,
    Time = t.LastWriteTime.ToString("yyyy-MM-dd HH:mm"),
    IsDirectory = t.IsDirectory,
    FullPath = t.Name
    });

  2. 删除远程文件\目录

    SftpClient client = new SftpClient(ip, port, userName, password);
    client.Connect(); // SftpClient的创建和连接的成本很低,可以在每次执行时都创建并连接
    SftpFileAttributes attrs = client.GetAttributes(deleteFilePath);
    if (attrs.IsDirectory)
    // 写个递归删除所有文件夹中的文件就行
    else
    client.DeleteFile(deleteFilePath);

  3. 重命名

    client.RenameFile(oldFilePath, newPath);

  4. 创建文件夹

    client.CreateDirectory(dirPath);

  5. 下载

    long totalLength = client.GetAttributes(remotePath).Size; // 获取一下远程文件的大小
    string tempPath = localPath + ".tmp"; // 先将远程文件保存至临时文件,结束后再删除掉.tmp后缀
    long offset = 0;
    if (File.Exits(tempPath))
    {
    offset = (new FileInfo(tempPath)).Length; // 因为提供的断点续传功能,所以临时文件的长度作为偏置,续传时就从这里开始
    if (offset >= totalLength)
    offset = totalLength; // 偏置为totalLength就算是下载完毕了
    }

    using StfpFileStream remoteStream = client.OpenRead(remotePath);
    remoteStream.Seek(offset, SeekOrigin.Begin); // SeekOrigin.Begin从文件开头开始偏移

    using FileStream localStream = new FileStream(tempPath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None, 256 * 1024); // 每次只读取256kb
    localStream.Seek(offset, SeekOrigin.Begin);

    byte[] buffer = new byte[256 * 1024];
    while(true)
    {
    if(!await Check())
    continue;

    复制代码
     int read = await remoteStream.ReadAsync(buffer.AsMemory(0, buffer.Length));  // Memory类似(指针 + 长度),由GC回收
     if (read == 0)
         break;
    
     await localStream.WriteAsync(buffer.AsMemory(0, read));

    }

    // 回收流资源 + 复制临时文件
    localStream.Dispose();
    if (File.Exits(localPath))
    File.Delete(localPath);

    File.Move(tempPath, localPath);

    async void Check()
    {
    TaskCompletionSource? tcs;
    lock(_lock)
    {
    if (isPaused)
    return false; // 这里省略了,isPaused为true时,while(true)那边不继续

    复制代码
         tcs = _pauseTcs;
     }
    
     if (tcs != null)
         await tcs.Task.ConfigureAwait(false);  // 在这里等

    }

    void Resume()
    {
    TaskCompletionSource? tcs;
    lock(_lock)
    {
    if (!isPaused)
    return;

    复制代码
         isPaused = false;
         tcs = _pauseTcs;
         _pauseTcs = null;
     }
    
     tcs?.TrySetResult(true);    

    }

    void Cancel()
    {
    TaskCompletionSource? tcs;
    lock(_lock)
    {
    if (isPaused)
    return;

    复制代码
         isPaused = true;
         _pauseTcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationAsynchronously);
     }
    
     tcs?.TrySetResult(false);    

    }

相关推荐
如若1236 小时前
Windows SSH + Headscale/Tailscale 组网及免密登录完整配置教程
运维·windows·ubuntu·ssh·内网穿透
lwx9148526 小时前
Docker-安装SSH服务
docker·容器·ssh
泛凡(Linyongui)7 小时前
基于 CW32L010 的智能厨卫调温旋钮方案--低成本 EC21 编码旋钮全解析
单片机·嵌入式硬件·c#
暴走约伯8 小时前
【VFX工具链源码拆解 02】告别机械劳动(上):一键统改百个子粒子颜色与批量重命名
3d·unity·c#·材质
信息安全失业大专人员10 小时前
每日了解一个智能体-WorkBuddy
开发语言·ai·c#·智能体
呆呆敲代码的小Y11 小时前
【实战精选面试题】C# 面试题详细解答,按难易程度排序
android·java·游戏·c#·游戏开发·unity面试题·c#面试题
淡海水11 小时前
09-01-内存-Unity资源生命周期全景
unity·c#·游戏引擎·.netcore·gc
snysy12 小时前
服务器安全加固与入侵检测实战:从SSH加固、防火墙策略到挖矿木马排查
服务器·安全·ssh
Linux_cy14 小时前
nginx 502 排查手册:九种原因分类、定位命令与检查顺序
linux·运维·服务器·网络·数据库·nginx·ssh
椒颜皮皮虾྅15 小时前
让 C# 读懂整张图:DeploySharp 驱动 PaddleOCR v4/v5/v6,打通 OCR 全流程
开发语言·人工智能·深度学习·学习·c#·ocr·cuda