底层连接已关闭:接收时发生意外错误
我在这里是因为我在通过ftp协议下载一些文件时遇到了问题。 这很奇怪,因为它偶尔发生,甚至对于同一个文件也是如此。
只是一个精度:我正在下载非常大的文件(从500 Mo到30Go)
以下是我的函数返回的exception类型:(抱歉,这是法语)
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 Download(string srcDirectoryPath, string file, string destDirectoryPath, int attemptLimitNb, int delay) { int attemptNb = 0; bool downloadFailed; Dictionary result = new Dictionary(); 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 Download(string srcDirectoryPath, string file, string destDirectoryPath) { Exception downloadFailed = null; Dictionary result = new Dictionary(); 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; }
存在方法:
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在调试模式下测试了我的代码,实际上上面的Exception是前一个的结果。 (我无法知道,因为我只写了一个日志文件中返回的最后一个Exception)
这是最初的例外:
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.
第二个例外是由下载方法代码的这一部分引起的:
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
增加超时可能至少是一个好主意。
这可能是Windows防火墙设置问题的症状。 在“服务”界面中禁用“应用层网关服务”为我修复了它。
这个post有很多信息:
尝试设置:
request.EnableSsl = true