파일 컬렉션을 다운로드하기 위해 FTP 웹 요청 모음을 만들려고합니다.FTP 요청을 생성하는 여러 스레드가있는 ThreadPool이 시간 초과되었습니다.
단일 스레드에서이 작업이 올바르게 수행되었지만 지금은 여러 스레드로 작업하려고했지만 시간 초과 예외가 발생했습니다.
그것은 처음 두 파일을 다운로드하는 것으로 보인다internal static void DownloadLogFiles(IEnumerable<string> ftpFileNames, string localLogsFolder)
{
BotFinder.DeleteAllFilesFromDirectory(localLogsFolder);
var ftpWebRequests = new Collection<FtpWebRequest>();
// Create web request for each log filename
foreach (var ftpWebRequest in ftpFileNames.Select(filename => (FtpWebRequest) WebRequest.Create(filename)))
{
ftpWebRequest.Credentials = new NetworkCredential(BotFinderSettings.FtpUserId, BotFinderSettings.FtpPassword);
ftpWebRequest.KeepAlive = false;
ftpWebRequest.UseBinary = true;
ftpWebRequest.CachePolicy = NoCachePolicy;
ftpWebRequest.Method = WebRequestMethods.Ftp.DownloadFile;
ftpWebRequests.Add(ftpWebRequest);
}
var threadDoneEvents = new ManualResetEvent[ftpWebRequests.Count];
for (var x = 0; x < ftpWebRequests.Count; x++)
{
var ftpWebRequest = ftpWebRequests[x];
threadDoneEvents[x] = new ManualResetEvent(false);
var threadedFtpDownloader = new ThreadedFtpDownloader(ftpWebRequest, threadDoneEvents[x]);
ThreadPool.QueueUserWorkItem(threadedFtpDownloader.PerformFtpRequest, localLogsFolder);
}
WaitHandle.WaitAll(threadDoneEvents);
}
class ThreadedFtpDownloader
{
private ManualResetEvent threadDoneEvent;
private readonly FtpWebRequest ftpWebRequest;
/// <summary>
///
/// </summary>
public ThreadedFtpDownloader(FtpWebRequest ftpWebRequest, ManualResetEvent threadDoneEvent)
{
this.threadDoneEvent = threadDoneEvent;
this.ftpWebRequest = ftpWebRequest;
}
/// <summary>
///
/// </summary>
/// <param name="localLogsFolder">
///
/// </param>
internal void PerformFtpRequest(object localLogsFolder)
{
try
{
// TIMEOUT IS HAPPENING ON LINE BELOW
using (var response = ftpWebRequest.GetResponse())
{
using (var responseStream = response.GetResponseStream())
{
const int length = 1024*10;
var buffer = new Byte[length];
var bytesRead = responseStream.Read(buffer, 0, length);
var logFileToCreate = string.Format("{0}{1}{2}", localLogsFolder,
ftpWebRequest.RequestUri.Segments[3].Replace("/", "-"),
ftpWebRequest.RequestUri.Segments[4]);
using (var writeStream = new FileStream(logFileToCreate, FileMode.OpenOrCreate))
{
while (bytesRead > 0)
{
writeStream.Write(buffer, 0, bytesRead);
bytesRead = responseStream.Read(buffer, 0, length);
}
}
}
}
threadDoneEvent.Set();
}
catch (Exception exception)
{
BotFinder.HandleExceptionAndExit(exception);
}
}
}
하지만 (이 개 내가 믿고있어 스레드를 사용하여) : 내가 아주 간단 뭔가를보고 싶어하지만, 여기에
그것을 밖으로 작동하지 수 있다고 생각하는 것은 코드 이 완료 및 응용 프로그램이 다음 파일로 이동할 때 시간 초과가 발생하는 것 같습니다.
시간이 초과 된 FTPWebRequest가 유효하고 파일이 존재한다는 것을 확인할 수 있습니다. 연결이되어있을 수도 있습니다.
코멘트를 게시하려고했지만 아마 쉽게는 대답 읽기 : 나는 Timeout.Infinite에 ftpRequest.Timout 속성을 설정하면,
첫째, 시간 제한 문제는 그러나 무한 제한 시간을 가진 사라진다 아마 모범 사례가 아닙니다. 그래서 내가 볼 수있는 코드를 디버깅 ...
이 다른 방법으로 해결하는 이동하는 것을 선호 거라고는 얻을 때까지 :
ThreadPool.QueueUserWorkItem(threadedFtpDownloader.PerformFtpRequest, localLogsFolder);
그것은 각 FTP 웹 요청에 대한 PerformFtpRequest 방법에 들어가 ftpWebRequest.GetResponse()를 호출하지만 처음 두 요청에 대해서만 계속 진행합니다. 나머지 요청은 계속 활성화되지만 처음 두 가지가 완료 될 때까지 더 이상 진행되지 않습니다. 따라서 기본적으로 시작하기 전에 다른 요청이 완료되기를 기다리는 동안 열어 둡니다.
이 문제에 대한 해결책은 모든 요청이 즉시 실행되도록 허용하는 것입니다 (ConnectionLimit 속성은 여기에 아무런 영향을 미치지 않습니다). 실제로 응답을 사용할 준비가 될 때까지 GetResponse를 호출하지 못하도록합니다.
이 문제를 해결하는 가장 좋은 방법은 무엇입니까? 내가 생각하고있는 것처럼 보일 수있는 모든 것은 내가 피하고 싶은 해피 솔루션이다.
고마워!
감사 메이트. foreach 루프 내에서 FtpWebRequests를 작성했지만 동일한 문제가 발생하는 코드를 추가하려고했습니다. 연결 한계를 설정해야하는 곳입니까? – timothyclifford
자세한 내용이 담긴 질문/답변 링크가 추가되었습니다. ServicePoint는 머리가 몇 번 튀어 나올 때까지 들어 본 적이없는 것들 중 하나입니다. –