【问题标题】:FTP error: 530 Sorry, Only 5 connections per host are allowedFTP 错误:530 抱歉,每台主机只允许 5 个连接
【发布时间】:2019-12-09 10:15:20
【问题描述】:

我有一个效果很好的 FTP 解决方案。但是过了一段时间,大概 20-30 分钟,我会收到这个错误:
530 抱歉,每个主机只允许 5 个连接

我已经搜索过这个问题,但没有真正找到任何解决方案。 我有不同的线程调用该函数,但只允许最多每 2 秒调用一次该函数。 我正在使用: using 语句,但我想我不想使用:

request.KeepAlive = false;

以确保连接将被关闭。正如我之前被告知在使用“ConnectionGroupName”时在“ServicePoint”中打开它,因为打开一个新连接会耗费资源并且保持打开更顺畅。

我认为但不确定。请告诉我这是否是一个不好的方法。但是当这个错误发生时。我喜欢关闭所有连接,在这种情况下是 5 个连接,所以它从零连接开始。这可能吗?由于我不确定如何在代码中调用这些连接,我将如何在代码中执行此操作?

        public async Task<List<String>> FtpGetFiles(String host, String folderpath, String user_name, String password)
        {
            List<String> serverfileLIST = new List<String>(); String error = "";
            try
            {
                var request = (FtpWebRequest)WebRequest.Create(host + "/" + folderpath + "/");
                request.Credentials = new NetworkCredential(user_name, password);
                request.Method = WebRequestMethods.Ftp.ListDirectory;
                request.ConnectionGroupName = host.Replace(".", "").Replace(":", "").Replace("/", "").Replace("-", "").Replace("_", "") + user_name;
                request.ServicePoint.ConnectionLimit = 4;
                request.Timeout = 20000;

                using (var responseWeb = await request.GetResponseAsync())
                {
                    var response = (FtpWebResponse)responseWeb;
                    if (response.StatusDescription.Contains("150") || //150 opening binary mode data connection for file list
                        response.StatusDescription.Contains("226")) 
                    {
                        using (StreamReader streamReader = new StreamReader(response.GetResponseStream()))
                        {
                            while (streamReader.Peek() >= 0)
                            {
                                serverfileLIST.Add(streamReader.ReadLine());
                            }
                        }
                        return serverfileLIST;
                    }
                    else { error = response.StatusDescription; }
                }
            }
            catch (WebException ex) { String status = ((FtpWebResponse)ex.Response).StatusDescription; error = status; }
            return serverfileLIST;
        }

编辑:
我附上了一个network.txt文件。我可以在自己的日志文件中看到,此时 GMT,我收到以下错误:
2019 年 12 月 9 日 16:09:40 530 抱歉,每台主机只允许 5 个连接
2019 年 12 月 9 日 16:09:42 530 抱歉,每个主机只允许 5 个连接

附加的network.txt文件也是格林威治标准时间在下面的链接中,我想知道是否可以追踪问题是什么以及如何解决?
network.txt

我可以在 txt 文件中找到它所在的那些行:
System.Net 信息:0:[14868] FtpControlStream#13919402 - 发送命令 [PASS ********] System.Net 信息:0:[14868] FtpControlStream#13919402 - 收到响应 [530 抱歉,每个主机只允许 5 个连接] System.Net 信息:0:[14868] FtpWebRequest#45677341::(释放 FTP 连接#13919402。) System.Net 错误:0:[14868] FtpWebRequest#45677341::EndGetResponse 中的异常-远程服务器返回错误:(530)未登录.. 在 System.Net.FtpWebRequest.EndGetResponse(IAsyncResult asyncResult)

【问题讨论】:

  • 我认为这不是客户端问题。而是服务器错误地识别出客户端已经关闭了连接。无论如何,可以肯定的是,启用日志记录并检查日志文件。甚至更好地交叉检查客户端和服务器日志文件。另请参阅stackoverflow.com/q/9664650/850848
  • 问题是,如果我完全关闭我的应用程序并直接打开它。然后它可以立即从 FTP 服务器上传/获取文件/下载,因为它几乎感觉任何对象/连接都以某种方式处理。否则,我可能会等待一个多小时,它不会连接到 FTP。但是一旦我关闭/打开应用程序,它就会直接运行。这有什么线索吗?
  • 我无权访问 FTP 服务器,因为它是免费服务器,所以我无法检查那边的任何内容。
  • 好的,所以至少发布客户端日志文件。
  • 是的,谢谢,我现在就这样做。重现我认为的问题可能需要一些时间。

标签: c# ftp


【解决方案1】:

每 2 秒调用一次的最大吞吐量并不能阻止外部线程调用超过 5 个连接。试想一下,您与服务器的连接暂时会很慢,或者您请求的列表会很长。下载可能需要比平时更多的时间(假设由于某种原因需要 15 秒)。因为完成需要更多时间,您最终会达到 5 个并发连接的上限并收到错误,因为您将在之前的下载完成之前发起新的调用。

您可以使用SemaphoreSlim 将所有对您的方法FtpGetFiles 的调用“排队”。这将确保您的线程执行的并发调用不超过 5 个。当一个调用结束时,信号量会释放一个点,然后另一个调用会开始。

看起来像这样:

public class TaskQueue
{
    private readonly SemaphoreSlim semaphore;
    private int pendingTasks;
    private int runningTasks;

    public TaskQueue(int maxConcurrencyLevel = 5)
    {
        semaphore = new SemaphoreSlim(maxConcurrencyLevel);
    }

    private async Task AddTask(Func<Task> task)
    {
        Interlocked.Increment(ref pendingTasks);
        await semaphore.WaitAsync();

        Interlocked.Decrement(ref pendingTasks);
        Interlocked.Increment(ref runningTasks);

        try
        {
            await task();
        }
        finally
        {
            Interlocked.Decrement(ref runningTasks);
            semaphore.Release();
        }
    }
}

每个调用你的方法的线程都会调用这个:

TaskQueue.AddTask(async () => await FtpGetFiles(host, folderpath, username, password));

【讨论】:

    猜你喜欢
    • 2017-02-23
    • 2016-11-07
    • 2017-02-28
    • 1970-01-01
    • 2021-06-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多