gpt4 book ai didi

c# - FTP 轮询器偶尔会挂起文件下载,直到重新启动

转载 作者:行者123 更新时间:2023-11-30 16:59:49 25 4
gpt4 key购买 nike

我有一个 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;`

最佳答案

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

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

文档中特别提到了这一点:

If the SynchronizingObject property is null, the Elapsed event is raised on a ThreadPool thread. If the processing of the Elapsed event lasts longer than Interval, the event might be raised again on another ThreadPool thread. In this situation, the event handler should be reentrant.

假设您确实在使用 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();
}

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

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

关于c# - FTP 轮询器偶尔会挂起文件下载,直到重新启动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23160585/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com