白码一号的博客园

最近由于项目安全需要,将之前的ftp上传文件的方式,改用ftps

因为不太了解这个东西便开始了踩坑之旅

首先,最近在ubuntu 上搭建了这个服务

流程可以参考这些博客(部署网上的资源很多)

https://www.jianshu.com/p/f666278dc3b7

https://www.jianshu.com/p/413ac3ab26a3

https://blog.csdn.net/hdxyzlh_0225/article/details/50923185

ftps呢是在ftp的服务的前提上加上了 证书,保证在传输的过程中数据不是明文,防止被抓包泄露敏感信息

部署的流程也在是一个完整的ftp服务上再去加证书

然后我这边把我服务器上的配置拉一下给大家参考一下

我这边配置的 ssl 隐式连接

# Example config file /etc/vsftpd.conf
#
# The default compiled in settings are fairly paranoid. This sample file
# loosens things up a bit, to make the ftp daemon more usable.
# Please see vsftpd.conf.5 for all compiled in defaults.
#
# READ THIS: This example file is NOT an exhaustive list of vsftpd options.
# Please read the vsftpd.conf.5 manual page to get a full idea of vsftpd's
# capabilities.
#
#
# Run standalone? vsftpd can run either from an inetd or as a standalone
# daemon started from an initscript.
listen=NO
#
# This directive enables listening on IPv6 sockets. By default, listening
# on the IPv6 "any" address (::) will accept connections from both IPv6
# and IPv4 clients. It is not necessary to listen on *both* IPv4 and IPv6
# sockets. If you want that (perhaps because you want to listen on specific
# addresses) then you must run two copies of vsftpd with two configuration
# files.
listen_ipv6=YES
#
# Allow anonymous FTP? (Disabled by default).
anonymous_enable=NO
#
# Uncomment this to allow local users to log in.
local_enable=YES
#
# Uncomment this to enable any form of FTP write command.
write_enable=YES #
# Default umask for local users is 077. You may wish to change this to 022,
# if your users expect that (022 is used by most other ftpd's)
#local_umask=022
#
# Uncomment this to allow the anonymous FTP user to upload files. This only
# has an effect if the above global write enable is activated. Also, you will
# obviously need to create a directory writable by the FTP user.
#anon_upload_enable=YES
#
# Uncomment this if you want the anonymous FTP user to be able to create
# new directories.
#anon_mkdir_write_enable=YES
#
# Activate directory messages - messages given to remote users when they
# go into a certain directory.
dirmessage_enable=YES
#
# If enabled, vsftpd will display directory listings with the time
# in your local time zone. The default is to display GMT. The
# times returned by the MDTM FTP command are also affected by this
# option.
use_localtime=YES
#
# Activate logging of uploads/downloads.
xferlog_enable=YES
#
# Make sure PORT transfer connections originate from port 20 (ftp-data).
connect_from_port_20=YES
#
# If you want, you can arrange for uploaded anonymous files to be owned by
# a different user. Note! Using "root" for uploaded files is not
# recommended!
#chown_uploads=YES
#chown_username=whoever
#
# You may override where the log file goes if you like. The default is shown
# below.
#xferlog_file=/var/log/vsftpd.log
#
# If you want, you can have your log file in standard ftpd xferlog format.
# Note that the default log file location is /var/log/xferlog in this case.
#xferlog_std_format=YES
#
# You may change the default value for timing out an idle session.
#idle_session_timeout=600
#
# You may change the default value for timing out a data connection.
#data_connection_timeout=120
#
# It is recommended that you define on your system a unique user which the
# ftp server can use as a totally isolated and unprivileged user.
#nopriv_user=ftpsecure
#
# Enable this and the server will recognise asynchronous ABOR requests. Not
# recommended for security (the code is non-trivial). Not enabling it,
# however, may confuse older FTP clients.
#async_abor_enable=YES
#
# By default the server will pretend to allow ASCII mode but in fact ignore
# the request. Turn on the below options to have the server actually do ASCII
# mangling on files when in ASCII mode.
# Beware that on some FTP servers, ASCII support allows a denial of service
# attack (DoS) via the command "SIZE /big/file" in ASCII mode. vsftpd
# predicted this attack and has always been safe, reporting the size of the
# raw file.
# ASCII mangling is a horrible feature of the protocol.
#ascii_upload_enable=YES
#ascii_download_enable=YES
#
# You may fully customise the login banner string:
#ftpd_banner=Welcome to blah FTP service.
#
# You may specify a file of disallowed anonymous e-mail addresses. Apparently
# useful for combatting certain DoS attacks.
#deny_email_enable=YES
# (default follows)
#banned_email_file=/etc/vsftpd.banned_emails
#
# You may restrict local users to their home directories. See the FAQ for
# the possible risks in this before using chroot_local_user or
# chroot_list_enable below.
#chroot_local_user=YES
#
# You may specify an explicit list of local users to chroot() to their home
# directory. If chroot_local_user is YES, then this list becomes a list of
# users to NOT chroot().
# (Warning! chroot'ing can be very dangerous. If using chroot, make sure that
# the user does not have write access to the top level directory within the
# chroot)
#chroot_local_user=YES
#chroot_list_enable=YES
# (default follows)
#chroot_list_file=/etc/vsftpd.chroot_list
#
# You may activate the "-R" option to the builtin ls. This is disabled by
# default to avoid remote users being able to cause excessive I/O on large
# sites. However, some broken FTP clients such as "ncftp" and "mirror" assume
# the presence of the "-R" option, so there is a strong case for enabling it.
#ls_recurse_enable=YES
#
# Customization
#
# Some of vsftpd's settings don't fit the filesystem layout by
# default.
#
# This option should be the name of a directory which is empty. Also, the
# directory should not be writable by the ftp user. This directory is used
# as a secure chroot() jail at times vsftpd does not require filesystem
# access.
secure_chroot_dir=/var/run/vsftpd/empty
#
# This string is the name of the PAM service vsftpd will use.
pam_service_name=vsftpd
#
# This option specifies the location of the RSA certificate to use for SSL
# encrypted connections. #rsa_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
#rsa_private_key_file=/etc/ssl/private/ssl-cert-snakeoil.key ssl_enable=YES
ssl_tlsv1=YES
ssl_sslv2=NO
ssl_sslv3=NO allow_anon_ssl=NO force_local_data_ssl=YES force_local_logins_ssl=YES listen_port=10012 rsa_cert_file=/etc/ssl/private/vsftpd.pem
rsa_private_key_file=/etc/ssl/private/vsftpd.pem implicit_ssl=YES connect_from_port_20=NO debug_ssl=YES local_root=/home/uftp/testFiles #
# Uncomment this to indicate that vsftpd use a utf8 filesystem.
#utf8_filesystem=YES

这个是FileZilla 连接工具的设置()

配置完后,工具能正常连接上,现在开始上代码  FluentFTP用的版本是 FluentFTP, Version=37.0.2.0  最新的版本代码有变化

// See https://aka.ms/new-console-template for more information
using FluentFTP;
using System.Net;
using System.Net.Security;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using System.Text; Console.WriteLine("Hello, World!"); string path = @"C:\Users\36493\Desktop\Test\UploadFileFtps\UploadFileFtps\2022-04-29182023.xml"; //创建目录
UploadToFtpFileHelper.CreateFileContent("2021/05/06/test"); //下载文件
//UploadToFtpFileHelper.DownloadFile(@"C:\Users\36493\Desktop\test002\111.txt", @"111.txt"); //上传文件
UploadToFtpFileHelper.UploadFile(path, @"2021/05/06/test/2022-04-29182023.xml");
public static class UploadToFtpFileHelper
{
//普通的ftp
private static string ftp_postUrl = "ftp://xx.xxx.x.xxx/";
private static string ftp_user = "xxxxx";
private static string ftp_pwd = "xxxxx"; //使用ssl通讯加密的方式连接ftp
private static string ftps_postUrl = "xx.xxx.x.xxx";
private static string ftps_user = "xxx";
private static string ftps_pwd = "xxxx";
private static int ftps_port = xx; #region Ftps private static FtpClient ftpClient = null; private static async Task<FtpClient> ConnectionFtp()
{
// 创建 FTP client
FtpClient client = new FtpClient(ftps_postUrl);
// 如果您不指定登录凭证,我们将使用"anonymous"用户帐户
client.Credentials = new NetworkCredential(ftps_user, ftps_pwd);
client.Port = ftps_port;
//选择证书连接的方式 TLS
client.SslProtocols = System.Security.Authentication.SslProtocols.Tls | System.Security.Authentication.SslProtocols.Ssl2 | System.Security.Authentication.SslProtocols.Ssl3;
client.Encoding = System.Text.Encoding.UTF8;
client.EncryptionMode = FtpEncryptionMode.Explicit;//ssl链接错误
client.ValidateCertificate += new FtpSslValidation(OnValidateCertificate);//证书验证
void OnValidateCertificate(FtpClient control, FtpSslValidationEventArgs e)
{
//在这里添加逻辑以测试证书是否有效
e.Accept = true;
}
var connect = client.AutoConnect();//根据验证过程,远程证书无效
if (!client.IsConnected)
{
Console.WriteLine("连接建立失败");
throw new Exception("连接建立失败");
}
return client;
} /// <summary>
/// 从ftp下载文件(ssl)
/// </summary>
/// <param name="localPath">要下载到本地哪儿</param>
/// <param name="ftpFilePath">ftp的文件路径</param>
public static async Task<FtpStatus> DownloadFile(string localPath, string ftpFilePath)
{
ftpClient = ftpClient == null ? await ConnectionFtp() : ftpClient;
FtpStatus status = ftpClient.DownloadFile(localPath, ftpFilePath);
//ftpClient.Disconnect();
return status;
} /// <summary>
/// 上传文件到ftp(ssl)
/// </summary>
/// <param name="localPath">本地的文件路径,完整的</param>
/// <param name="ftpFilePath">要上传到的地址</param>
/// <returns></returns>
public static async Task<FtpStatus> UploadFile(string localPath, string ftpFilePath)
{
ftpClient = ftpClient == null ? await ConnectionFtp() : ftpClient;
FtpStatus status = ftpClient.UploadFile(localPath, ftpFilePath);
//ftpClient.Disconnect();
return status;
} /// <summary>
/// 创建文件目录
/// </summary>
public static async Task<bool> CreateFileContent(string createPath)
{
ftpClient = ftpClient == null ? await ConnectionFtp() : ftpClient;
bool result = ftpClient.CreateDirectory(createPath);
//ftpClient.Disconnect();
return result;
} public static void Mains()
{
// 创建 FTP client
FtpClient client = new FtpClient("10.168.1.128");
// 如果您不指定登录凭证,我们将使用"anonymous"用户帐户
client.Credentials = new NetworkCredential("tgy", "test123456");
client.Port = 10012;
//选择证书连接的方式 TLS
client.SslProtocols = System.Security.Authentication.SslProtocols.Tls | System.Security.Authentication.SslProtocols.Ssl2 | System.Security.Authentication.SslProtocols.Ssl3;
client.Encoding = System.Text.Encoding.UTF8;
client.EncryptionMode = FtpEncryptionMode.Explicit;//ssl链接错误
client.ValidateCertificate += new FtpSslValidation(OnValidateCertificate);//证书验证
void OnValidateCertificate(FtpClient control, FtpSslValidationEventArgs e)
{
//在这里添加逻辑以测试证书是否有效
e.Accept = true;
} //开始连接Server
try
{
var connect = client.AutoConnect();//根据验证过程,远程证书无效
if (!client.IsConnected)
{
Console.WriteLine("连接建立失败");
} foreach (FtpListItem item in client.GetListing("testFiles"))
{
//如果是 file
if (item.Type == FtpFileSystemObjectType.File)
{
// get the file size
long size = client.GetFileSize(item.FullName);
}
// 获取文件或文件夹的修改日期/时间
DateTime time = client.GetModifiedTime(item.FullName);
// 计算服务器端文件的哈希值(默认算法)
//FtpHash hash = client.GetHash(item.FullName);
} if (client.DirectoryExists("test"))
{ } var gg = client.DownloadFile(@"C:\Users\36493\Desktop\test002\111.txt", @"111.txt"); var oo = client.UploadFile(@"C:\Users\36493\Desktop\test002\yyds.txt", "yyds.txt");
}
catch (Exception ex)
{ throw;
}
} #endregion #region Ftp
/// <summary>
/// 上传项目指定的文件到ftp服务器
/// </summary>
/// <param name="localfilePath">服务文件路径</param>
/// <param name="fileName">上传文件路径及名称(包含后缀)</param>
/// <exception cref="Exception"></exception>
public static async void UploadToFtp(string localfilePath, string urlfileName)//, UploadType Type
{
if (!File.Exists(localfilePath))
{
throw new FileNotFoundException("未获取到本地服务器文件!");
} if (!CheckDirectoryExist(urlfileName))
{
FtpCheckExis(urlfileName);
}
await UploadDetails_Ftp(localfilePath, urlfileName);
} /// <summary>
/// 把一个ftp文件从指定路径复制到 另一个路径下
/// </summary>
/// <param name="oldfilePath">旧的ftp的url</param>
/// <param name="newfilePath">新的ftp的url</param>
/// <returns></returns>
public static async Task<string> CopyFtpToFtp(string oldfilePath, string newfilePath)
{
return "";
} private static async Task UploadDetails_Ftp(string localfilePath, string urlfileName)
{
FileInfo fileInfo = new FileInfo(localfilePath);
var reqFTP = (FtpWebRequest)FtpWebRequest.Create(ftp_postUrl + urlfileName);
reqFTP.EnableSsl = true;
reqFTP.Credentials = new NetworkCredential(ftp_user, ftp_pwd);
reqFTP.KeepAlive = false;//默认位true,链接不会被关闭,再一个指令之后被执行
reqFTP.Method = WebRequestMethods.Ftp.UploadFile; //指定执行什么命令
reqFTP.UseBinary = true;//指定数据传输类型
reqFTP.ContentLength = fileInfo.Length;//上传文件通知服务器,文件的大小
int buffLength = 2048;//缓冲大小设置位2kb
byte[] buff = new byte[buffLength];
int contentlen; FileStream fs = fileInfo.OpenRead();
try
{
Stream stream = await reqFTP.GetRequestStreamAsync();//把上传的文件写入流
contentlen = fs.Read(buff, 0, buff.Length);//每次读取文件的流的2kb while (contentlen != 0)//流内容没有结束
{
stream.Write(buff, 0, contentlen);
contentlen = fs.Read(buff, 0, buff.Length);
}
stream.Close();
fs.Close();
}
catch (Exception ex)
{
}
} /// <summary>
/// 判断ftp服务器上是否存在该目录
/// </summary>
/// <param name="ftpPath">ftp路径目录</param>
/// <param name="dirName">目录上的文件夹名称</param>
/// <returns></returns>
private static bool CheckDirectoryExist(string dirName)
{
bool flag = true;
try
{
var reqFTP = (FtpWebRequest)FtpWebRequest.Create(ftp_postUrl + dirName);
reqFTP.Credentials = new NetworkCredential(ftp_user, ftp_pwd);
reqFTP.Method = WebRequestMethods.Ftp.ListDirectory; FtpWebResponse response = (FtpWebResponse)reqFTP.GetResponse();
response.Close();
}
catch (Exception ex)
{
flag = false;
}
return flag;
} /// <summary>
/// 创建文件夹
/// </summary>
/// <param name="ftpPath">ftp路径</param>
/// <param name="dirName">创建文件夹名称</param>
private static async Task MakerDir(string dirName)
{
FtpWebRequest reqFtp;
try
{
reqFtp = (FtpWebRequest)FtpWebRequest.Create((ftp_postUrl + dirName).Trim());
reqFtp.Method = WebRequestMethods.Ftp.MakeDirectory;
reqFtp.UseBinary = true;
reqFtp.Credentials = new NetworkCredential(ftp_user, ftp_pwd);
FtpWebResponse resp = (FtpWebResponse)reqFtp.GetResponse();
Stream ftpStream = resp.GetResponseStream();
ftpStream.Close();
resp.Close();
}
catch (Exception ex)
{
}
} /// <summary>
/// 判断文件的目录是否存在
/// </summary>
public static void FtpCheckExis(string urlFilepath)
{
string fullDir = urlFilepath.Substring(0, urlFilepath.LastIndexOf("/"));
string[] dirs = fullDir.Split('/');
string curDir = "/";
for (int i = 0; i < dirs.Length; i++)
{
string dir = dirs[i];
if (dir != null && dir.Length > 0)
{
try
{
curDir += dir + "/";
FtpMakerDir(curDir);
}
catch (Exception)
{
}
}
}
} /// <summary>
/// 新建文件目录
/// </summary>
/// <param name="file"></param>
/// <returns></returns>
public static bool FtpMakerDir(string file)
{
FtpWebRequest req = (FtpWebRequest)WebRequest.Create(ftp_postUrl + file);
req.Credentials = new NetworkCredential(ftp_user, ftp_pwd);
req.Method = WebRequestMethods.Ftp.MakeDirectory;
try
{
FtpWebResponse request = (FtpWebResponse)req.GetResponse();
request.Close();
}
catch (Exception)
{
req.Abort();
return false;
}
req.Abort();
return true;
}
#endregion }

好,到这里踩坑完毕
经过项目复盘优化

性能更高、更快速的ftps的连接方式如下

public async Task<FtpClient> Connection(FtpConfigure ftpConfigure)
{
// 创建 FTP client
Temporaryclient = new FtpClient(ftpConfigure.ftps_Url);
// 如果您不指定登录凭证,我们将使用"anonymous"用户帐户
Temporaryclient.Credentials = new NetworkCredential(ftpConfigure.ftps_user, ftpConfigure.ftps_pwd);
Temporaryclient.Port = ftpConfigure.ftps_port;
//选择证书连接的方式 TLS
Temporaryclient.SslProtocols = System.Security.Authentication.SslProtocols.Tls | System.Security.Authentication.SslProtocols.Tls11 | System.Security.Authentication.SslProtocols.Tls12 | System.Security.Authentication.SslProtocols.Tls13;
Temporaryclient.Encoding = System.Text.Encoding.UTF8;
Temporaryclient.EncryptionMode = FtpEncryptionMode.Implicit;//ssl链接错误
Temporaryclient.DataConnectionType = FtpDataConnectionType.PASV;
Temporaryclient.ValidateCertificate += new FtpSslValidation(OnValidateCertificate);//证书验证
void OnValidateCertificate(FtpClient control, FtpSslValidationEventArgs e)
{
//在这里添加逻辑以测试证书是否有效
e.Accept = true;
}
//var connect = Temporaryclient.AutoConnect();//根据验证过程,远程证书无效
Temporaryclient.Connect();
if (!Temporaryclient.IsConnected)
{
Console.WriteLine("上级ftps连接建立失败");
_logger.LogError("上级ftps连接建立失败");
}
return Temporaryclient;
}

如果遇到并发传输记得枷锁哦

public async Task<FtpStatus> DownloadFile(string localPath, string ftpFilePath, SystemType type)
{
FtpStatus status = FtpStatus.Success;
try
{
lock (_locker)
{
SelectConnection(type);
if (!Publicclient.IsConnected)
{
_logger.LogError("ftp连接失败");
} status = Publicclient.DownloadFile(localPath, ftpFilePath);
}
//ftpClient.Disconnect();
}
catch (Exception ex)
{
_logger.LogError("请求失败,原因:"+ex);
}
return status;
}

上面服务连接较慢 继续更新继续优化

using FluentFTP;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Service.IntelligentRemotePatrol.Application.Contracts.Common;
using Service.IntelligentRemotePatrol.ConfigOptions;
using Service.IntelligentRemotePatrol.Enums;
using Service.IntelligentRemotePatrol.Helper;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Security.Authentication;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Modularity; namespace Service.IntelligentRemotePatrol.Application.Common
{ public class UploadToFtpService : IUpLoadFtpFileService
{
private object _lockerArest = new object();
private object _locker = new object();
private object _locker_that = new object(); private readonly ILogger<UploadToFtpService> _logger; public UploadToFtpService(ServiceConfigurationContext context, ILogger<UploadToFtpService> logger)
{
_logger = logger; #region ftps
var _appConfig = context.Services.BuildServiceProvider().GetService<IOptions<AppConfig>>()?.Value ??
new AppConfig();
List<FtpConfigure> ftpConfigureList = new List<FtpConfigure>();
FtpConfigure SuperiorFtpConfigure1 = new FtpConfigure
{
ftps_port = string.IsNullOrEmpty(_appConfig.FTPSuperiorSettings.Port) ? 0 : Convert.ToInt32(_appConfig.FTPSuperiorSettings.Port),
ftps_pwd = _appConfig.FTPSuperiorSettings.Pwd,
ftps_user = _appConfig.FTPSuperiorSettings.Account,
ftps_Url = _appConfig.FTPSuperiorSettings.Ip,
Type = SystemType.Superior,
};
FtpConfigure AreaFtpConfigure1 = new FtpConfigure
{
ftps_port = string.IsNullOrEmpty(_appConfig.FTPAreaSettings.Port) ? 0 : Convert.ToInt32(_appConfig.FTPAreaSettings.Port),
ftps_pwd = _appConfig.FTPAreaSettings.Pwd,
ftps_user = _appConfig.FTPAreaSettings.Account,
ftps_Url = _appConfig.FTPAreaSettings.Ip,
Type = SystemType.Area,
};
FtpConfigure EdgeFtpConfigure1 = new FtpConfigure
{
ftps_port = string.IsNullOrEmpty(_appConfig.FTPEdgeSettings.Port) ? 0 : Convert.ToInt32(_appConfig.FTPEdgeSettings.Port),
ftps_pwd = _appConfig.FTPEdgeSettings.Pwd,
ftps_user = _appConfig.FTPEdgeSettings.Account,
ftps_Url = _appConfig.FTPEdgeSettings.Ip,
Type = SystemType.Edge,
};
if (!string.IsNullOrEmpty(SuperiorFtpConfigure1.ftps_Url))
{
ftpConfigureList.Add(SuperiorFtpConfigure1);
}
if (!string.IsNullOrEmpty(AreaFtpConfigure1.ftps_Url))
{
ftpConfigureList.Add(AreaFtpConfigure1);
}
if (!string.IsNullOrEmpty(EdgeFtpConfigure1.ftps_Url))
{
ftpConfigureList.Add(EdgeFtpConfigure1);
}
Task.Run(() => ConnectionFtp(ftpConfigureList)).Wait();
//ftps
#endregion
} /// <summary>
/// 临时
/// </summary>
private FtpClient Temporaryclient = null; /// <summary>
/// 上级的ftps
/// </summary>
private FtpClient Superiorclient = null; /// <summary>
/// 区域的ftps
/// </summary>
private FtpClient Areaclient = null; /// <summary>
/// 边缘的ftps
/// </summary>
private FtpClient Edgeclient = null; /// <summary>
/// 公共的
/// </summary>
private FtpClient Publicclient = null; public async void ConnectionFtp(List<FtpConfigure> ftpConfigures)
{
foreach (var item in ftpConfigures)
{
try
{
switch (item.Type)
{
case SystemType.Superior:
Superiorclient = await Connection(item);
break;
case SystemType.Area:
Areaclient = await Connection(item);
break;
case SystemType.Edge:
Edgeclient = await Connection(item);
break;
default:
break;
}
}
catch (Exception ex)
{
_logger.LogError(ex, "ftps连接建立异常。");
}
}
} public async Task<FtpClient> Connection(FtpConfigure ftpConfigure)
{
// 创建 FTP client
Temporaryclient = new FtpClient(ftpConfigure.ftps_Url);
// 如果您不指定登录凭证,我们将使用"anonymous"用户帐户
Temporaryclient.Credentials = new NetworkCredential(ftpConfigure.ftps_user, ftpConfigure.ftps_pwd);
Temporaryclient.Port = ftpConfigure.ftps_port;
//选择证书连接的方式 TLS
//Temporaryclient.SslProtocols = System.Security.Authentication.SslProtocols.Tls | System.Security.Authentication.SslProtocols.Tls11 | System.Security.Authentication.SslProtocols.Tls12 | System.Security.Authentication.SslProtocols.Tls13;
Temporaryclient.Encoding = System.Text.Encoding.UTF8;
Temporaryclient.ValidateCertificate += Temporaryclient_ValidateCertificate; Temporaryclient.Config.EncryptionMode = FtpEncryptionMode.Implicit;
Temporaryclient.Config.DataConnectionType = FtpDataConnectionType.PASV;
Temporaryclient.Config.SocketKeepAlive = true;
Temporaryclient.Config.SslProtocols = System.Security.Authentication.SslProtocols.Tls
| SslProtocols.Tls11
| SslProtocols.Tls12
| SslProtocols.Tls13; //var connect = Temporaryclient.AutoConnect();//根据验证过程,远程证书无效
Temporaryclient.Connect();
if (!Temporaryclient.IsConnected)
{
Console.WriteLine("上级ftps连接建立失败");
_logger.LogError("上级ftps连接建立失败");
}
return Temporaryclient;
} private void Temporaryclient_ValidateCertificate(FluentFTP.Client.BaseClient.BaseFtpClient control, FtpSslValidationEventArgs e)
{
e.Accept = true;
} /// <summary>
/// 从ftp下载文件(ssl)
/// </summary>
/// <param name="localPath">要下载到本地哪儿</param>
/// <param name="ftpFilePath">ftp的文件路径</param>
/// <param name="type">//1上级 2区域 3边缘</param>
public async Task<FtpStatus> DownloadFile(string localPath, string ftpFilePath, SystemType type)
{
FtpStatus status = FtpStatus.Success;
try
{
lock (_locker)
{
SelectConnection(type);
if (!Publicclient.IsConnected)
{
_logger.LogError("ftp连接失败");
} status = Publicclient.DownloadFile(localPath, ftpFilePath);
}
//ftpClient.Disconnect();
}
catch (Exception ex)
{
_logger.LogError("请求失败,原因:" + ex);
}
return status;
} /// <summary>
/// 从ftp下载文件(ssl) 下载目录下的所有文件
/// </summary>
/// <param name="localPath">要下载到本地哪儿</param>
/// <param name="ftpFilePath">ftp的文件路径</param>
/// <param name="type">//1上级 2区域 3边缘</param>
public async Task<MemoryStream> Download(string ftpFilePath, SystemType type, MemoryStream stream)
{
MemoryStream memoryStream = new MemoryStream();
try
{
lock (_locker)
{
SelectConnection(type); //var exist = Publicclient.FileExists(ftpFilePath);
//_logger.LogInformation($"ft当前路径:{ftpFilePath} 文件是否存在:{exist}"); //var size = Publicclient.GetFileSize(ftpFilePath);
//_logger.LogInformation($"ft当前路径:{ftpFilePath} 文件大小:{size}"); Publicclient.DownloadStream(memoryStream, ftpFilePath); //ftpClient.Disconnect();
}
}
catch (Exception ex)
{
_logger.LogError($"ftp下载图失败,当前路径:{ftpFilePath}原因:" + ex.Message);
}
return memoryStream;
} public async Task<FtpListItem[]> GetListing(string url, SystemType type)
{
SelectConnection(type);
return Publicclient.GetListing(url);
} /// <summary>
/// 上传Http文件到ftp(ssl) 先下载http的文件地址的图片再上传到指定ftp路径
/// </summary>
/// <param name="localPath"></param>
/// <param name="ftpFilePath"></param>
/// <param name="type">//1上级 2区域 3边缘</param>
/// <returns></returns>
public async Task<FtpStatus> ConnectionFtpHttp(List<string> fileurl, string ftpFilePath, SystemType type)
{
SelectConnection(type);
FtpStatus status = FtpStatus.Success;
try
{
if (ftpFilePath.Substring(ftpFilePath.Length - 1, 1) == "/")
{
CheckThePathExists(ftpFilePath);
}
else
{
if (ftpFilePath.Contains("/"))
{
var path = ftpFilePath.Substring(0, ftpFilePath.LastIndexOf("/") + 1);
CheckThePathExists(path);
}
} foreach (var item in fileurl)
{
//string fileName = string.Empty;
//if (item.Contains("/"))
//{
// fileName = item.Split("/")[item.Split("/").Length - 1];
//}
_logger.LogInformation("下载地图文件的url为:" + item);
status = Publicclient.UploadBytes(RestClientHelper.DownloadData(item), ftpFilePath);
}
//ftpClient.Disconnect();
}
catch (Exception ex)
{
throw new UserFriendlyException(ex.Message);
}
return status;
} /// <summary>
/// 上传Http文件到ftp(ssl) 先下载http的文件地址的图片再上传到指定ftp路径
/// </summary>
/// <param name="fileurl">文件地址集合</param>
/// <param name="fileNames">文件名称集合,与文件地址一对一,如果不传,则自动默认取文件路径上的文件名称</param>
/// <param name="ftpFilePath">要存储的文件路径</param>
/// <param name="type">//1上级 2区域 3边缘</param>
/// <returns></returns>
public async Task<FtpStatus> ConnectionFtpHttpList(List<string> fileurl, string ftpFilePath, SystemType type, List<string> fileNames)
{
SelectConnection(type);
FtpStatus status = FtpStatus.Success;
try
{
if (ftpFilePath.Substring(ftpFilePath.Length - 1, 1) == "/")
{
CheckThePathExists(ftpFilePath);
}
else
{
if (ftpFilePath.Contains("/"))
{
var path = ftpFilePath.Substring(0, ftpFilePath.LastIndexOf("/") + 1);
CheckThePathExists(path);
}
}
string fileName = string.Empty;
for (int i = 0; i < fileurl.Count; i++)
{
if (fileNames != null && fileNames.Count > 0 && fileNames.Count > i && !string.IsNullOrWhiteSpace(fileNames[i]))
{
fileName = fileNames[i];
}
else
{
if (fileurl[i].Contains("/"))
{
fileName = fileurl[i].Split("/")[fileurl[i].Split("/").Length - 1];
}
else
{
fileName = DateTime.Now.ToString("yyyyMMddHHmmssfff") + fileurl[i].Split(".")[fileurl[i].Split(".").Length - 1];
}
}
status = Publicclient.UploadBytes(RestClientHelper.DownloadData(fileurl[i]), ftpFilePath + fileName); }
//ftpClient.Disconnect();
}
catch (Exception ex)
{
throw new UserFriendlyException(ex.Message);
}
return status;
} /// <summary>
/// 上传本地文件到ftp服务器
/// </summary>
/// <param name="filesDic">文件名为key,全路径为value</param>
/// <param name="ftpFilePath"></param>
/// <param name="type"></param>
/// <returns></returns>
public async Task<FtpStatus> UploadLocalFiles(Dictionary<string, string> filesDic, string ftpFilePath, SystemType type)
{
SelectConnection(type);
FtpStatus status = FtpStatus.Success; try
{
if (ftpFilePath.Substring(ftpFilePath.Length - 1, 1) == "/")
{
CheckThePathExists(ftpFilePath);
}
else
{
if (ftpFilePath.Contains("/"))
{
var path = ftpFilePath.Substring(0, ftpFilePath.LastIndexOf("/") + 1);
CheckThePathExists(path);
}
}
foreach (var item in filesDic)
{
status = Publicclient.UploadFile(item.Value, ftpFilePath + item.Key);//目前就一个文件,status就这样了先
} }
catch (Exception ex)
{
throw;
}
return status;
} /// <summary>
/// 上传Btye[]文件到ftp(ssl)
/// </summary>
/// <param name="fileurl">图片数组</param>
/// <param name="ftpFilePath">要保存的路径</param>
/// <param name="fileName">文件名称</param>
/// <param name="type">//1上级 2区域 3边缘</param>
/// <returns></returns>
public async Task<FtpStatus> ConnectionFtpByByte(byte[] fileurl, string ftpFilePath, string fileName, SystemType type)
{ FtpStatus status = FtpStatus.Success;
try
{
lock (_locker_that)
{
SelectConnection(type);
if (ftpFilePath.Substring(ftpFilePath.Length - 1, 1) == "/")
{
CheckThePathExists(ftpFilePath);
}
else
{
if (ftpFilePath.Contains("/"))
{
var path = ftpFilePath.Substring(0, ftpFilePath.LastIndexOf("/") + 1);
CheckThePathExists(path);
}
} status = Publicclient.UploadBytes(fileurl, ftpFilePath + fileName);
} }
catch (Exception ex)
{
_logger.LogError(ex, "图片上次至FTP服务器异常。");
//throw new UserFriendlyException(ex.Message);
status = FtpStatus.Failed;
}
return status;
} /// <summary>
/// 上传Btye[]文件到ftp(ssl)
/// </summary>
/// <param name="fileurl">图片数组</param>
/// <param name="ftpFilePath">要保存的路径</param>
/// <param name="fileName">文件名称</param>
/// <param name="type">//1上级 2区域 3边缘</param>
/// <returns></returns>
public async Task<FtpStatus> ConnectionFtpByByte(Stream fileStream, string ftpFilePath, string fileName, SystemType type)
{
FtpStatus status = FtpStatus.Success;
try
{
lock (_locker_that)
{
SelectConnection(type);
if (ftpFilePath.Substring(ftpFilePath.Length - 1, 1) == "/")
{
CheckThePathExists(ftpFilePath);
}
else
{
if (ftpFilePath.Contains("/"))
{
var path = ftpFilePath.Substring(0, ftpFilePath.LastIndexOf("/") + 1);
CheckThePathExists(path);
}
}
status = Publicclient.UploadStream(fileStream, ftpFilePath + fileName);
} }
catch (Exception ex)
{
_logger.LogError(ex, "图片上次至FTP服务器异常。");
//throw new UserFriendlyException(ex.Message);
status = FtpStatus.Failed;
}
return status;
} /// <summary>
/// 上传文件到ftp(ssl)
/// </summary>
/// <param name="localPath">本地的文件路径,完整的</param>
/// <param name="ftpFilePath">要上传到的地址</param>
/// <param name="type">//1上级 2区域 3边缘</param>
/// <returns></returns>
public async Task<FtpStatus> UploadFileFtps(string localPath, string ftpFilePath, SystemType type)
{
FtpStatus status = FtpStatus.Success;
try
{
lock (_lockerArest)
{
SelectConnection(type);
string pathStr = ftpFilePath;
if (ftpFilePath.Contains("/"))
{
var path = ftpFilePath.Substring(0, ftpFilePath.LastIndexOf("/") + 1);
CheckThePathExists(path);
pathStr = ftpFilePath.Substring(ftpFilePath.LastIndexOf("/") + 1);
}
status = Publicclient.UploadFile(localPath, ftpFilePath);//ftpFilePath
//status = Publicclient.UploadFile(@"C:\Users\36493\Desktop\测试文件\2022-10-27180030189.xml", pathStr);
//ftpClient.Disconnect();
}
}
catch (Exception ex)
{
throw new UserFriendlyException(ex.Message);
}
return status;
} /// 2022年10/27 号出现了 文件能上传但是无文件大小的问题 持续到28号上午 问题还没找到 突然又正常了 ……………………………………………………心情复杂
/// <summary>
/// 上传文件到ftp(ssl)
/// </summary>
/// <param name="localPath">本地的文件路径,完整的</param>
/// <param name="ftpFilePath">要上传到的地址</param>
/// <param name="type">//1上级 2区域 3边缘</param>
/// 用流的形式
/// <returns></returns>
public async Task<FtpStatus> UploadFileFtps_bug(string localPath, string ftpFilePath, SystemType type)
{
string name = string.Empty;
if (!localPath.Contains('/'))
{
name = localPath.Split("\\")[(localPath.Split("\\").Length - 1)];
}
else
{
name = localPath;
}
string path = string.Empty;
SelectConnection(type);
FtpStatus status = FtpStatus.Success;
try
{
string pathStr = ftpFilePath;
if (ftpFilePath.Contains("/"))
{
path = ftpFilePath.Substring(0, ftpFilePath.LastIndexOf("/") + 1);
CheckThePathExists(path);
pathStr = ftpFilePath.Substring(ftpFilePath.LastIndexOf("/") + 1);
} // 打开文件
FileStream fileStream = new FileStream(localPath, FileMode.Open, FileAccess.Read, FileShare.Read);
// 读取文件的 byte[]
// 把 byte[] 转换成 Stream
MemoryStream stream = new MemoryStream();
//byte[] bytes = new byte[fileStream.Length];
//fileStream.Read(bytes, 0, bytes.Length);
await fileStream.CopyToAsync(stream);
//fileStream.Close();
try
{
await ConnectionFtpByByte(stream, path, name, SystemType.Area);
//await ConnectionFtpByByte(stream.ToArray(), path, name, SystemType.Area);
//await ConnectionFtpByByte(stream.ToArray(), "/", name, SystemType.Area);
}
catch (Exception ex)
{
_logger.LogError(ex, "区域收到边缘上报图片,存储到ftp报错。");
} //status = Publicclient.UploadFile(localPath, ftpFilePath);
//status = Publicclient.UploadFile(localPath, pathStr);
//ftpClient.Disconnect();
}
catch (Exception ex)
{
throw new UserFriendlyException(ex.Message);
}
return status;
} /// <summary>
/// 修改文件名
/// </summary>
/// <param name="path"></param>
/// <param name="name"></param>
/// <param name="type"></param>
/// <returns></returns>
/// <exception cref="UserFriendlyException"></exception>
public async Task<FtpStatus> Rename(string path, string name, SystemType type)
{
SelectConnection(type);
FtpStatus status = FtpStatus.Success;
try
{
if (!Publicclient.DirectoryExists(path))
{
return FtpStatus.Success;
}
Publicclient.Rename(path, name);
//ftpClient.Disconnect();
}
catch (Exception ex)
{
throw new UserFriendlyException(ex.Message);
}
return status;
} private void SelectConnection(SystemType type)
{
try
{
switch (type)
{
case SystemType.Superior:
Publicclient = Superiorclient;
break;
case SystemType.Area:
Publicclient = Areaclient;
break;
case SystemType.Edge:
Publicclient = Edgeclient;
break;
default:
break;
} Publicclient.ValidateCertificate += Publicclient_ValidateCertificate;
}
catch (Exception ex)
{
_logger.LogError(ex, "验证ftps的证书异常:" + ex);
} }
/// <summary>
/// //证书验证
/// </summary>
/// <param name="control"></param>
/// <param name="e"></param>
private void Publicclient_ValidateCertificate(FluentFTP.Client.BaseClient.BaseFtpClient control, FtpSslValidationEventArgs e)
{
e.Accept = true;
} /// <summary>
/// 判断路径是否存在 不在就创建
/// </summary>
/// <param name="ftpFilePath"></param>
private void CheckThePathExists(string ftpFilePath)
{
try
{
Publicclient.ValidateCertificate += Publicclient_ValidateCertificate1;
if (!Publicclient.DirectoryExists(ftpFilePath))
{
var state = Publicclient.CreateDirectory(ftpFilePath);
}
}
catch (Exception ex)
{
throw new UserFriendlyException(ex.Message);
}
} private void Publicclient_ValidateCertificate1(FluentFTP.Client.BaseClient.BaseFtpClient control, FtpSslValidationEventArgs e)
{
//在这里添加逻辑以测试证书是否有效
e.Accept = true;
}
}
}

再次补充

public async Task<FtpClient> Connection(FtpConfigure ftpConfigure)
{
try
{
var ftpconfig = new FtpConfig();
ftpconfig.ConnectTimeout = 60 * 1000;
ftpconfig.ReadTimeout = 60 * 1000;
ftpconfig.DataConnectionConnectTimeout = 60 * 1000;
ftpconfig.DataConnectionReadTimeout = 60 * 1000;
// 创建 FTP client
var Temporaryclient = new FtpClient(ftpConfigure.ftps_Url, ftpConfigure.ftps_user, ftpConfigure.ftps_pwd, ftpConfigure.ftps_port, ftpconfig, _logger); // 如果您不指定登录凭证,我们将使用"anonymous"用户帐户 Temporaryclient.Encoding = System.Text.Encoding.UTF8;
Temporaryclient.ValidateCertificate += Temporaryclient_ValidateCertificate;
Temporaryclient.Config.ValidateAnyCertificate = true;
Temporaryclient.Config.EncryptionMode = FtpEncryptionMode.Implicit;
Temporaryclient.Config.DataConnectionType = FtpDataConnectionType.PASV;
Temporaryclient.Config.SocketKeepAlive = true;
Temporaryclient.Config.SslProtocols = System.Security.Authentication.SslProtocols.Tls
| SslProtocols.Tls11
| SslProtocols.Tls12
| SslProtocols.Tls13;
//Temporaryclient.Config.SslProtocols = SslProtocols.Tls13; //var connect = Temporaryclient.AutoConnect();//根据验证过程,远程证书无效
Temporaryclient.Connect();
if (!Temporaryclient.IsConnected)
{
Console.WriteLine("连接建立失败");
_logger.LogError("连接建立失败:" + ftpConfigure.ToJson());
}
_logger.LogInformation($"ftps连接成功IP:{ftpConfigure.ftps_Url}");
return Temporaryclient;
}
catch (Exception ex)
{
_logger.LogError(ex, "连接建立失败" + ftpConfigure.ToJson());
}
return Temporaryclient;
} private void Temporaryclient_ValidateCertificate(FluentFTP.Client.BaseClient.BaseFtpClient control, FtpSslValidationEventArgs e)
{
e.Accept = true;
}

C# .netCore 上传文件到ftps/ftp的更多相关文章

  1. FTP主动模式上传文件时返回"ftp: accept: Resource temporarily unavailable"

    FTP主动模式上传文件时返回 Passive mode off ftp: accept: Resource temporarily unavailable 这个问题要从ftp的2种模式说起 PORT ...

  2. 实现用http上传文件,用ftp下载文件

    1.ftp配置 1.检查安装vsftpd软件 使用如下命令#rpm -qa |grep vsftpd可以检测出是否安装了vsftpd软件, 如果没有安装,使用YUM命令进行安装. 2.启动服务 使用v ...

  3. 本地向服务器上传文件的方式-FTP工具上传

    笔者负责的一个研究生会的项目,向服务器端传项目代码,用到了FTP工具,这里总结下: FTP方式的步骤: 1,服务器端配置好FTP,(若没有,可网上下载一个服务器端安装的FTP).停止服务后,可以配置账 ...

  4. MacOS上传文件到windows ftp时链接文件不见了

    最近打包遇到了一个问题,打包完MAC的sdk包后,得到的是一个framework的文件夹,我们需要将这个framework传到ftp服务器上,另外,还要把这个文件夹下的Release文件夹里的文件替换 ...

  5. Android上传文件之FTP

    android客户端实现FTP文件(包括图片)上传应该没什么难度.写下来就了为了记录一下,望能帮到新手. 需要用到 commons-net-3.0.1.jar,后面附上jar包. 直接上代码: /** ...

  6. Java ftp 上传文件和下载文件

    今天同事问我一个ftp 上传文件和下载文件功能应该怎么做,当时有点懵逼,毕竟我也是第一次,然后装了个逼,在网上找了一段代码发给同事,叫他调试一下.结果悲剧了,运行不通过.(装逼失败) 我找的文章链接: ...

  7. JAVA调用FTP上传文件

    import java.io.File; import java.io.FileInputStream; import org.apache.commons.net.ftp.FTP; import o ...

  8. java 上传文件到 ftp 服务器

    1.  java 上传文件到 ftp 服务器 package com.taotao.common.utils; import java.io.File; import java.io.FileInpu ...

  9. java 上传文件到FTP(centos中的ftp服务)

    ftp服务器系统:centos7 提供ftp的服务:vsftpd pom.xml 依赖 <dependency> <groupId>commons-net</groupI ...

  10. JAVA 实现FTP上传下载(sun.net.ftp.FtpClient)

    package com.why.ftp; import java.io.DataInputStream; import java.io.File; import java.io.FileInputSt ...

随机推荐

  1. 为什么Controller层注入的是Service接口,而不是ServiceImpl实现类

    转自csdn--https://blog.csdn.net/weixin_39565597/article/details/78078728 今天看代码发现,写法和自己理解的java写法不一致,就查找 ...

  2. angularjs 1.4.x 内部组件介绍

    内部Services 1, $cacheFactory angular 内部缓存类,构建一个缓存对象. var cache = $cacheFactory('cacheId'); expect($ca ...

  3. JMM(Java内存模型)笔记

    JMM介绍1.什么是JMM?2.JMM的三大特性:1.原子性2.可见性3.有序性3.关于同步的规定:4.解释说明JMM中的八种操作:1.什么是JMM?​ JMM 是Java内存模型( Java Mem ...

  4. 写一个PHP单例模式

    1 <?php 2 /** 3 * Created by PhpStorm. 5 * Date: 2019/1/29 6 * Time: 17:44 7 */ 8 9 namespace App ...

  5. dendrogram

    https://ww2.mathworks.cn/help/stats/dendrogram.html

  6. How to find WWN and WWPN of HBA card in Linux

    There are several ways to detect the WWN of a Fibre Channel (FC) HBA and their details in Linux/Unix ...

  7. VUE 一些小功能(查重、逻辑删除)

    查重就是在表中查找是否有该值,如果有返回0没有则返回1 在API写添加方法时可以直接通过该方法返回值进行添加,如果是0则添加,1则重名   不进行添加 逻辑删除就是在信息表中添加一个删除状态的字段,比 ...

  8. snorkel SentenceNgramViewer 标记时出现 Integrity Error

    Snorkel使用SQLAlchemy作为数据管理工具,在本地会生成一个.db文件,现有操作与.db文件中已有的记录重复,违反了数据库主键不能重复的性质 解决方式: You can load a la ...

  9. 招新题流程简介(WS2812)

    22物电科协软件招新题学习流程 有错误或者不当的地方请在评论区指出 题目简介 使用stm32驱动单一ws2812b灯珠实现呼吸灯效果,驱动及实现方法不限 演示效果 快速入门,在stm32核心板上点灯 ...

  10. linux 学习shell

    1. bash的父进程,子进程 [root@A~]# my_var=123[root@A~]# echo $my_var123[root@A~]# bash[root@A~]# [root@A~]# ...