34

我有一个用 .NET 3.5 编写的应用程序,它使用 FTP 从服务器上传/下载文件。该应用程序运行良好,但存在性能问题:

  1. 连接到 FTP 服务器需要很长时间。FTP 服务器位于不同的网络上,并具有 Windows 2003 Server (IIS FTP)。当多个文件排队等待上传时,从一个文件到另一个文件的更改使用 FTPWebRequest 创建一个新连接,这需要很长时间(大约 8-10 秒)。

  2. 是否可以重新使用连接?我不太确定 KeepAlive 属性。哪些连接保持活动和重用。

  3. Windows Server 2003 上的 IIS-FTP 不支持 SSL,因此任何人都可以通过 WireShark 等数据包嗅探器轻松查看用户名/密码。我发现 Windows Server 2008 在 IIS 7.0 的新版本中支持 SSL over FTP。

我基本上想提高我的应用程序的上传/下载性能。任何想法将不胜感激。

** 请注意,3 不是问题,但我希望人们对此发表评论

4

18 回答 18

41

I have done some experimentation (uploading about 20 files on various sizes) on FtpWebRequest with the following factors

KeepAlive = true/false

ftpRequest.KeepAlive = isKeepAlive;

Connnection Group Name = UserDefined or null

ftpRequest.ConnectionGroupName = "MyGroupName";

Connection Limit = 2 (default) or 4 or 8

ftpRequest.ServicePoint.ConnectionLimit = ConnectionLimit;

Mode = Synchronous or Async

see this example

My results:

  1. Use ConnectionGroupName,KeepAlive=true took (21188.62 msec)

  2. Use ConnectionGroupName,KeepAlive=false took (53449.00 msec)

  3. No ConnectionGroupName,KeepAlive=false took (40335.17 msec)

  4. Use ConnectionGroupName,KeepAlive=true;async=true,connections=2 took (11576.84 msec)

  5. Use ConnectionGroupName,KeepAlive=true;async=true,connections=4 took (10572.56 msec)

  6. Use ConnectionGroupName,KeepAlive=true;async=true,connections=8 took (10598.76 msec)

Conclusions

  1. FtpWebRequest has been designed to support an internal connection pool. To ensure, the connection pool is used, we must make sure the ConnectionGroupName is being set.

  2. Setting up a connection is expensive. If we are connecting to the same ftp server using the same credentials, having the keep alive flag set to true will minimize the number of connections setup.

  3. Asynchronous is the recommended way if you have a lot of files to ftp.

  4. The default number of connections is 2. In my environment, a connection limit of 4 will give to me the most overall performance gain. Increasing the number of connections may or may not improve performance. I would recommend that you have the connection limit as a configuration parameter so that you can tune this parameter in your environment.

Hope you would find this useful.

于 2010-06-23T01:32:10.983 回答
18

只要您可以并行启动多个连接,单个连接是否需要很长时间才能连接并不重要。如果您有许多项目要传输(例如数百个),那么使用BeginGetRequestStreamBeginGetResponse等异步方法并行启动数十甚至数百个 WebRequest 是有意义的。我从事的项目面临类似问题(连接/身份验证时间长),但通过并行发出许多调用,总体吞吐量实际上非常好。

如果您使用异步方法或同步方法,一旦您有许多(数十,数百)个请求,它也会产生巨大的差异。这不仅适用于您的 WebRequests 方法,还适用于您在获取上传/下载流后将使用的 Stream/写方法。提高 .Net 性能和可扩展性这本书有点过时了,但它的大部分建议仍然有效,并且可以在线免费阅读。

需要考虑的一件事是,ServicePointManager类潜伏在 Framwework 中,其唯一目的是:破坏您的性能。确保获取 URL 的 ServicePoint并将ConnectionLimit更改为合理的值(至少与您想要的并发请求数一样高)。

于 2009-06-25T08:07:12.013 回答
5

调试网络

简单网络调试的一些技巧:

  1. 检查从应用程序服务器 ping FTP 服务器时的响应时间。
  2. 检查跟踪路由的响应时间(tracert来自 DOS shell)。
  3. 使用命令从命令行传输文件ftp
  4. 通过 Telnet 连接到 FTP 服务器:telnet server 21

结果将为解决问题提供线索。

网络硬件

对于慢速跟踪路由:

  • 确定两台计算机出现网络问题的原因。
  • 升级最慢链接之间的网络硬件。

网络配置

对于缓慢的 ping:

  • 检查每台机器上的网络配置。
  • 确保设置是最佳的。

验证 API

缓慢的命令行 FTP 会话会告诉您问题与您正在使用的 FTP API 无关。它不会消除 API 作为潜在问题,但肯定会降低它的可能性。

网络错误

如果数据包在源和目标之间被丢弃,ping 会告诉你。您可能必须将数据包大小增加到 1500 字节才能看到任何错误。

FTP 队列服务器

如果您无法控制目标 FTP 服务器,请让中间服务器接收上传的文件。然后中介以任何速度将文件发送到远程服务器。这给人一种文件正在快速发送的错觉。但是,如果文件一上传就必须存在于远程服务器上,则此解决方案可能不可行。

FTP 服务器软件

在 FTP 服务器上使用不同的 FTP 守护程序,例如将ProFTPd作为Windows 服务。(ProFTPd 具有用于各种数据库的插件,允许使用 SQL 查询进行身份验证。)

FTP 服务器操作系统

基于 Unix 的操作系统可能比基于 Microsoft 的操作系统更好。

FTP客户端软件

有许多不同的 API 用于通过 FTP 发送和接收文件。可能需要一些工作才能使您的应用程序足够模块化,以便您可以简单地插入新的文件传输服务。这里列出了几个不同的 API 作为答案。

备用协议

如果 FTP 不是绝对要求,请尝试:

  • Windows 网络驱动器
  • HTTPS
  • scp、rsync 或类似程序(可能需要Cygwin )
于 2009-06-28T20:15:25.233 回答
4

此链接描述 ConnectionGroupName 和 KeepAlive 影响: WebRequest ConnectionGroupName

于 2010-10-13T12:23:36.187 回答
3

您绝对应该查看BITS,它是对 FTP 的重大改进。明文密码并不是 FTP 的唯一弱点。还有一个问题是预测它将为被动上传或下载打开的端口,以及客户端使用 NAT 或防火墙时的整体困难。

BITS 使用 IIS 扩展通过 HTTP/HTTPS 工作,并支持可以以低优先级安排的排队上传和下载。如果您在客户端和服务器上使用 Windows,它总体上比 FTP 灵活得多。

用于 PowerShell 的 BITS

.NET 的 BITS

于 2009-06-23T08:23:59.527 回答
2

我强烈建议.NET 和 Mono 的 Starksoft FTP/FTPS 组件。它有一个可以缓存和重用的连接对象。

于 2010-01-15T04:34:42.513 回答
2

就我个人而言,我已经迁移了我们所有的应用程序,不再使用 FTP 进行文件上传/下载,而是推出了基于 ASP.NET 中的 XML Web Services 的解决方案。

性能大大提高,安全性与您想要编码的一样多或少(并且您可以使用内置于 .NET 的东西)并且它都可以毫无问题地通过 SSL。

我们让客户的连接通过他们自己的防火墙的成功率远高于运行 FTP。

于 2009-06-22T11:59:20.410 回答
2

看看这个页面 - http://www.ietf.org/rfc/rfc959.txt

它说在连接时使用不同的端口以便能够重用连接。
那样有用吗?

于 2009-06-28T19:08:01.097 回答
1

要解决有关性能的问题,您只需设置:

ftpRequest.ConnectionGroupName = "MyGroupName"; ftpRequest.KeepAlive = false; ftpRequest.ServicePoint.CloseConnectionGroup("MyGroupName");

于 2012-08-04T12:18:45.030 回答
1

我建议切换到rsync
优点:
针对减少传输时间进行了优化。
支持 SSH 进行安全传输
使用 TCP 让您的 IT 部门/防火墙人员更快乐

缺点:
没有原生 .NET 支持
面向 linux 服务器安装 - 尽管有像DeltaCopy这样的不错的 Windows 端口

总的来说,虽然它是比 FTP 更好的选择

于 2009-06-27T15:23:01.823 回答
1

我使用 EDT 的 ftp 库取得了不错的效果:

http://www.enterprisedt.com/products/edtftpnet/overview.html

于 2009-06-27T16:06:58.407 回答
1

我知道这是一个旧线程,但我最近不得不经历类似的情况。

我们需要在 25 分钟内从 ftp 服务器下载 70 多个 XML 文件,而在此期间打开的连接不超过 5 个。

这些是我们尝试过的所有替代方案:

  • wget - 它很快,但每个 GET 都意味着一个新的连接。由于创建的连接数量,我们不得不停止。我们在使用 GETM 时遇到了一些问题,这些问题在网络上有很好的记录,所以这不是一个选择。
  • FtpWebRequest - 每个 Create 调用都会记录一个新连接,即使我们使用了 KeepAlive 和 ConnectionGroupName 属性。另外,它非常慢。
  • Webclient - 我们没有检查它是否为每个文件创建了一个新连接(尽管我认为它确实如此),但它复制了 1 个文件/分钟。所以这不是一个选择。

我们最终使用了老式的 ftp 批处理脚本。它很快,我只使用一个连接来下载所有文件。它不灵活,但比我尝试过的所有其他方法都要快得多(20 分钟内 75 个文件)。

于 2013-09-20T22:21:25.313 回答
0

KeepAlive 正在工作。FtpWebRequest 在内部缓存连接,因此可以在一段时间后重用它们。有关此机制的详细信息和说明,您可以查看ServicePoint

另一个很好的信息来源是查看 FtpWebRequest 源(您可以在 VS2008 上进行)。

于 2009-06-23T08:10:31.783 回答
0

AFAIK,每个 FtpWebRequest 都必须建立一个新的连接——包括登录到服务器。如果您想加快 FTP 传输速度,我建议您使用备用 FTP 客户端。其中一些备用客户端可以登录,然后使用相同的命令连接执行多个操作。

此类客户端的示例包括: http: //www.codeproject.com/KB/IP/FtpClient.aspx,其中还很好地解释了为什么这些库可以比标准 FtpWebRequest 和http://www.codeproject 运行得更快。 com/KB/macros/ftp_class_library.aspx看起来也很简单。

就我个人而言,在引入 FtpWebRequest 之前的 .NET 1.1 天,我将自己的 FTP 实现回滚到了 .NET 2.0 之后的版本中。

于 2009-06-27T15:08:04.630 回答
0

单点建议:

较低的缓冲区/块大小会显着降低性能

原因:更多的磁盘 i/o、内存 i/o、ftp 流初始化和更多的因素

于 2012-02-21T10:51:03.617 回答
0

我为此工作了几天......速度真的很低,与FileZilla相比没有什么可比性......最后我用多线程解决了。10 个线程为下载建立连接给了我很好的速度,甚至可以改进更多.. 使用标准的 ftprequest 配置

PeticionFTP.ConnectionGroupName = "MyGroupName"
PeticionFTP.ServicePoint.ConnectionLimit = 4
PeticionFTP.ServicePoint.CloseConnectionGroup("MyGroupName")

PeticionFTP.KeepAlive = False 
PeticionFTP.UsePassive = False

PeticionFTP.UseBinary = True

PeticionFTP.Credentials = New NetworkCredential(lHost.User, lHost.Password)
于 2015-09-27T20:49:22.887 回答
0

我对 FtpWebRequest 做了一些基准测试,类似于上面@Sid 的响应。将 KeepAlive 设置为 true 确实有所改善,但在我的测试中没有异步调用。测试包括

1) FtpWebRequest 用于检查文件是否存在 2) FtpWebRequest 用于上传 3) FtpWebRequest 用于重命名服务器上的文件

Test FTP client 30 files of size 5 Kbytes took ... 14.897 seconds Test upload (alive true, connection name) 30 files of size 5 Kbytes took ... 34.229 seconds Test async(alive true, connection name) 30 files of size 5 Kbytes took ... 40.659 seconds Test send thread (alive true, connection name) 30 files of size 5 Kbytes took ... 38.926 seconds, 30 files

改进的是使用 Socket 类实现的 FTP 客户端

基准在这里

https://github.com/pedro-vicente/ftp_t

于 2018-05-08T18:14:37.837 回答
-1

试试下面的代码,你会得到更好的性能:

private void Upload144_Click(object sender, EventArgs e)
{
    OpenFileDialog fileobj = new OpenFileDialog();
    fileobj.InitialDirectory = "C:\\";
    //fileobj.Filter = "Video files (*.mp4)";
    //fileobj.ShowDialog();

    if (fileobj.ShowDialog() == DialogResult.OK)
    {
        if (fileobj.CheckFileExists)
        {
            string test = Properties.Settings.Default.Connection;
            SqlConnection con = new SqlConnection(test);
            con.Open();
            string correctfilename = System.IO.Path.GetFileName(fileobj.FileName);
            SqlCommand cmd = new SqlCommand("Insert into Path(ID,Path5) VALUES   ((select isnull(MAX(id),0) + 1 from Path),'\\Videos\\" + correctfilename + "')", con);

            cmd.ExecuteNonQuery();

            string path = Application.StartupPath.Substring(0, Application.StartupPath.Length - 10);
            con.Close();

            //For Progressbar
            DataTable dt = new DataTable();
       //   SqlDataAdapter da = new SqlDataAdapter(cmd);
       //   da.Fill(dt);

            timer5.Enabled = true;

            // FOR FtpServer File Upload::
            string uploadfile = fileobj.FileName;
            string uploadFileName = new FileInfo(uploadfile).Name;

            string uploadUrl = "ftp://ftp.infotech.com/";
            FileStream fs = new FileStream(uploadfile, FileMode.Open, FileAccess.Read);
            try
            {
                long FileSize = new FileInfo(uploadfile).Length; // File size of file being uploaded.
                Byte[] buffer = new Byte[FileSize];

                fs.Read(buffer, 0, buffer.Length);

                fs.Close();
                fs = null;
                string ftpUrl = string.Format("{0}/{1}", uploadUrl, uploadFileName);
                FtpWebRequest requestObj = FtpWebRequest.Create(ftpUrl) as FtpWebRequest;
                requestObj.Method = WebRequestMethods.Ftp.UploadFile;
                requestObj.Credentials = new NetworkCredential("test@sample.com", "test@123");
                Stream requestStream = requestObj.GetRequestStream();
                requestStream.Write(buffer, 0, buffer.Length);

                requestStream.Flush();
                requestObj = null;
            }
            catch (Exception ex)
            {
                //MessageBox.Show("File upload/transfer Failed.\r\nError Message:\r\n" + ex.Message, "Succeeded", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }
    }
}
于 2016-02-15T12:09:39.103 回答