【问题标题】:FTP poller occasionally hangs on file download until restartFTP 轮询器偶尔会挂起文件下载,直到重新启动
【发布时间】:2014-04-18 19:07:11
【问题描述】:

我有一个 Windows 服务,它每三秒轮询一次远程 FTP 服务器。它检查目录中的文件,下载所有存在的文件,并在下载后删除这些文件。平均文件大小为 10 KB,很少会达到 100 KB 的范围。

偶尔(我没有注意到任何模式),WebClient 会抛出以下内容:

System.Net.WebException: The operation has timed out.
at System.Net.WebClient.OpenRead(Uri address)

它将为一个或多个文件执行此操作,通常是当时远程目录中的任何文件。它将无限期地继续这样做,在每个轮询间隔搅动“卡住”的文件。奇怪的是,当我停止/启动 Windows 服务时,“卡住”的文件会完美下载,并且轮询/下载会在很长一段时间内再次运行。这很奇怪,因为我是这样下载的:

private object _pollingLock = new object();

public void PollingTimerElapsed(object sender, ElapsedEventArgs e)
{
    if(Monitor.TryEnter(_pollingLock);
    {
        //FtpHelper lists content of files in directory
        ...

        foreach(var file in files)
        {
            using(var client = new WebClient())
            {
                client.Proxy = null;
                using(var data = client.OpenRead(file.Uri)
                {
                    //Use data stream to write file locally
                    ...
                }
            }
            //FtpHelper deletes the file
            ...
        } 
    }
    //Release the _pollingLock inside a finally
}

我假设为每个文件打开和关闭一个新连接(除非 .NET 在幕后做某事)。如果文件下载有问题,它将在下一个轮询间隔(3 秒内)重新进行重试。为什么重启服务会让一切正常?

我开始怀疑这个问题与缓存(文件或连接)有关。最近我尝试进入 Internet Explorer 并清除缓存。大约 30 秒左右后,所有下载的文件都没有重新启动服务。但是,下一批要到的文件又都挂了。我可能会尝试添加这样的一行:

client.CachePolicy = new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore);

或尝试禁用 KeepAlives,但我想在开始尝试随机的东西之前获得一些意见。

那么:是什么导致偶尔超时?为什么重启服务会起作用?为什么清除缓存有效?

更新

大约两周前,我制定了上述缓存策略和保持活动更改。从那以后,我刚刚获得了第一次超时。它似乎提高了频率,但遗憾的是,它仍在发生。

更新

根据要求,这就是我开始 Timer 的方式:

_pollingTimer.AutoReset = true; 
_pollingTimer.Elapser += PollingTimerElapsed; 
_pollingTimer.Interval = 10000; 
_pollingTimer.Enabled = true;`

【问题讨论】:

  • 每三秒轮询一次服务器?哇。您是否考虑过安装该资源?
  • 遗憾的是,我没有该选项,因为我无法控制服务器、数据源或下载机制的选择。不过,幸运的是,我是唯一一个轮询此服务器的人。我承认 3 秒是极端的,但我需要对这些数据进行低延迟。
  • 也许你用尽了可用端口的数量:stackoverflow.com/a/1087525/578411
  • 您是否启用了网络跟踪? msdn.microsoft.com/en-us/library/ty48b824(v=vs.110).aspx 你也检查了 DefaultConnectionLimit:msdn.microsoft.com/en-us/library/…
  • @Simon Mourier,过去几天我一直在调整ServicePoint 的值,正在等待看看效果如何。谢谢。

标签: c# .net ftp windows-services webclient


【解决方案1】:

看起来您正在使用 System.Timers.Timer.Elapsed 事件开始处理。

我发现的一个问题是,如果您的 Elapsed 事件的执行时间比计时器间隔长,则可以在另一个线程中再次调用您的事件在它完成执行之前

这在文档中特别提到:

如果 SynchronizingObject 属性为 null,则 Elapsed 事件为 在 ThreadPool 线程上引发。如果处理 Elapsed 事件 持续时间长于间隔,该事件可能会再次引发另一个 线程池线程。在这种情况下,事件处理程序应该是 可重入。

假设您确实在使用 AutoReset=true 的普通计时器(默认情况下启用),首先要做的是解决这个潜在问题。您可以使用 SynchronizingObject,或者您可以执行以下操作:

//setup code
Timer myTimer = new Timer(30000);
myTimer.AutoReset = false;
....

//Elapsed handler
public void PollingTimerElapsed(object sender, ElapsedEventArgs e)
{
    //do what you currently do
    ...

    //when finished, kick off the timer again
    myTimer.Start();
}

无论哪种方式,主要是确保您的代码不会意外地被多个线程同时调用 - 如果发生这种情况,很有可能偶尔会有一个线程尝试从站点下载某些内容,而另一个线程线程同时删除文件。

你提到的事情,例如它只是偶尔发生,通常文件大小很小,通过重新启动等修复它会指向我这个问题的方向。

【讨论】:

  • 我已经在方法的开头使用了Monitor.TryEnter(object)。我将更新我的 sn-p 以反映这一点。不过这是个好主意。
  • 我认为您需要发布更多代码。从您所写的内容来看,一般方法应该有效。文件处理或 FTP 服务本身很可能存在更微妙的问题。
猜你喜欢
  • 2019-05-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-17
  • 1970-01-01
  • 2023-03-23
相关资源
最近更新 更多