Ftpプロトコルを介していくつかのファイルをダウンロードしているときに問題が発生したため、ここにいます。たまに発生し、同じ単一のファイルでも発生するため、奇妙です。
正確さ:非常に大きなファイル(500 Moから30Go)をダウンロードしています
これが私の関数によって返される例外の種類です:(申し訳ありませんがフランス語です)
System.Net.WebException: La connexion sous-jacente a été fermée : Une erreur inattendue s'est produite lors de la réception. à System.Net.FtpWebRequest.CheckError() à System.Net.FtpWebRequest.SyncRequestCallback(Object obj) à System.IO.Stream.Close() à System.Net.ConnectionPool.Destroy(PooledStream pooledStream) à System.Net.ConnectionPool.PutConnection(PooledStream pooledStream, Object owningObject, Int32 creationTimeout, Boolean canReuse) à System.Net.FtpWebRequest.FinishRequestStage(RequestStage stage) à System.Net.FtpWebRequest.SyncRequestCallback(Object obj) à System.Net.CommandStream.Abort(Exception e) à System.Net.CommandStream.CheckContinuePipeline() à System.Net.FtpDataStream.System.Net.ICloseEx.CloseEx(CloseExState closeState) à System.Net.FtpDataStream.Dispose(Boolean disposing) à System.IO.Stream.Close() à UtilityClasses.FTP.Download(String srcDirectoryPath, String file, String destDirectoryPath)
ダウンロードに使用するコードは次のとおりです。
ダウンロード方法:
public Dictionary<string, object> Download(string srcDirectoryPath, string file, string destDirectoryPath, int attemptLimitNb, int delay)
{
int attemptNb = 0;
bool downloadFailed;
Dictionary<string, object> result = new Dictionary<string,object>();
do
{
attemptNb++;
result = Download(srcDirectoryPath, file, destDirectoryPath);
downloadFailed = result["downloadfailed"] != null;
if (downloadFailed) Thread.Sleep((int)(1000 * delay));
}
while (downloadFailed && attemptNb < attemptLimitNb);
return result;
}
public Dictionary<string, object> Download(string srcDirectoryPath, string file, string destDirectoryPath)
{
Exception downloadFailed = null;
Dictionary<string, object> result = new Dictionary<string, object>();
bool fileFound = false;
try
{
if (destDirectoryPath == null || !Directory.Exists(destDirectoryPath)) throw new Exception("Download destination path does not exist");
if (file != null && file != "")
{
if (file.Contains("/"))
{
throw new Exception("Invalid file name. Impossible to download");
}
Uri serverUri;
if (srcDirectoryPath == null || srcDirectoryPath == "")
{
serverUri = new Uri("ftp://" + this.Server + "/" + file);
}
else if (Regex.IsMatch(srcDirectoryPath, "^/.*$") || Regex.IsMatch(srcDirectoryPath, "^.*/$"))
{
throw new Exception("Path must not start and end with '/'");
}
else
{
serverUri = new Uri("ftp://" + this.Server + "/" + srcDirectoryPath + "/" + file);
}
if (serverUri.Scheme != Uri.UriSchemeFtp) throw new Exception("server URI Scheme does not match FTP URI Scheme");
if (Exists(srcDirectoryPath, file))
{
fileFound = true;
FtpWebRequest downloadRequest = (FtpWebRequest)FtpWebRequest.Create(serverUri);
downloadRequest.Credentials = new NetworkCredential(UserName, Password);
downloadRequest.KeepAlive = false;
downloadRequest.Method = WebRequestMethods.Ftp.DownloadFile;
FtpWebResponse response = (FtpWebResponse)downloadRequest.GetResponse();
Stream responseStream = response.GetResponseStream();
FileStream fileStream = new FileStream(Path.Combine(destDirectoryPath, file), FileMode.Create);
byte[] buffer = new byte[2000];
int read = 0;
try
{
do
{
read = responseStream.Read(buffer, 0, buffer.Length);
fileStream.Write(buffer, 0, read);
fileStream.Flush();
}
while (read != 0);
}
catch (Exception e)
{
fileStream.Close();
responseStream.Close();
response.Close();
throw e;
}
fileStream.Close();
responseStream.Close();
response.Close();
}
}
}
catch (WebException webExcptn)
{
downloadFailed = webExcptn;
}
finally
{
result.Add("filefound", fileFound);
result.Add("downloadfailed", downloadFailed);
}
return result;
}
existsメソッド:
public bool Exists(string srcPath, string elementName)
{
if (elementName == null || elementName == "")
{
return false;
}
Uri serverUri;
bool res = false;
if (srcPath == null || srcPath == "")
{
serverUri = new Uri("ftp://" + this.Server);
}
else if (Regex.IsMatch(srcPath, "^/.*$") || Regex.IsMatch(srcPath, "^.*/$"))
{
throw new Exception("Path must not start and end with '/'");
}
else
{
serverUri = new Uri("ftp://" + this.Server + "/" + srcPath);
}
if (serverUri.Scheme != Uri.UriSchemeFtp) throw new Exception("server URI Scheme does not match FTP URI Scheme");
FtpWebRequest listingRequest = (FtpWebRequest)FtpWebRequest.Create(serverUri);
listingRequest.Credentials = new NetworkCredential(UserName, Password);
listingRequest.KeepAlive = false;
listingRequest.Method = WebRequestMethods.Ftp.ListDirectory;
FtpWebResponse response = (FtpWebResponse)listingRequest.GetResponse();
Stream responseStream = response.GetResponseStream();
StreamReader streamReader = new StreamReader(responseStream);
string ftpElementName;
do
{
ftpElementName = Path.GetFileName(streamReader.ReadLine());
if (ftpElementName == null) break;
else
{
string pattern = "^" + elementName.Replace("[", "\\[").Replace("]", "\\]").Replace("+", "[+]").Replace(".", "[.]") + "$";
if (Regex.IsMatch(ftpElementName, pattern, RegexOptions.IgnoreCase))
{
res = true;
}
}
}
while (ftpElementName != null && !res);
streamReader.Close();
responseStream.Close();
response.Close();
return res;
}
タイムアウトの問題かもしれませんが、よくわかりません。私は長い間答えを探しましたが、成功しませんでした。多分あなたの何人かは解決策を持っているでしょう。
///
編集:いくつかの進歩:
VSを使用してデバッグモードでコードをテストしましたが、実際、上記の例外は前の例外の結果です。 (ログファイルに返された最後の例外のみを書き込んだため、それを知ることができませんでした)
これが元の例外です:
Unable to read data from the transport connection: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected Host has failed to respond.
2番目の例外は、Downloadメソッドコードのこの部分が原因です。
catch (Exception e)
{
fileStream.Close();
responseStream.Close(); // <<<<<<<<<<<<<<
response.Close();
throw e;
}
私は調査を続けていますが、「タイムアウトpb」仮説が最も一貫しているようです。今夜は大きなタイムアウト値で試してみます。
ScottEの診断を強化し、より具体的にしたいだけです。タイムアウトが問題である可能性が最も高いです。
FtpWebRequestの.Net実装に誤りがあるか、 MSDNドキュメント にタイプミスがあり、FtpWebRequest.Timeoutのデフォルト値は-1(無限)ではありません。 100000(100秒)です。
さらに、別のタイムアウトの問題があります。いくつかのテストでは、responseStreamのタイムアウト値が常に300000(300秒)であることが示されています。この値がどのように割り当てられているのかわかりません。とにかく、この値は大きなファイルに対応するように変更する必要があります。
要約すると、解決策はFtpWebRequest.TimeoutとStream.Timeoutを十分に大きな値に設定することです。
試してみるべきことの良いスレッドは次のとおりです。
http://social.msdn.Microsoft.com/Forums/en/ncl/thread/47634ec2-4d40-4d3f-b075-8cc92bfa2b24
タイムアウトを増やすことは、少なくとも良い考えです。
設定してみてください:
request.EnableSsl = true
これは、Windowsファイアウォールの設定に関する問題の症状である可能性があります。 「services」インターフェースで「ApplicationLayerGateway Service」を無効にすると、修正されました。
このスレッドには多くの情報があります。