2011-06-10 16 views
16

Estoy aquí porque tengo un problema al descargar algunos archivos a través del protocolo ftp. Es extraño porque ocurre ocasionalmente e incluso para el mismo archivo individual.La conexión subyacente se cerró: Se produjo un error inesperado en una recepción

Sólo una precisión: estoy descargando archivos muy grandes (de 500 Mo para 30Go)

Estas son el tipo de excepciones devueltos por mi función: (lo siento que está en francés)

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)

Este es el código utilizado para descargar:

los métodos de descarga:

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; 
    } 

el método 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; 
    } 

tal vez es un problema de tiempo de espera, pero no se sabe muy bien. Busqué durante mucho tiempo una respuesta, pero sin éxito. Tal vez algunos de ustedes tendrán una solución.

///

EDIT: algunos progresos:

He probado mi código en modo de depuración, con el VS y de hecho la excepción anterior es la consecuencia de una anterior. (Yo no podía saber que porque yo sólo escribí la última excepción devuelta en un archivo de registro)

Aquí es la excepción original:

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. 

La segunda excepción es causado por esta parte del código de descarga método :

catch (Exception e) 
{ 
    fileStream.Close(); 
    responseStream.Close(); // <<<<<<<<<<<<<< 
    response.Close(); 
    throw e; 
} 

Me mantengo en mis investigaciones, pero parece que la hipótesis "timeout pb" es la más consistente. Lo intentaré con un gran valor de tiempo de espera esta noche.

+1

no se disculpe. El único francés que recuerdo es "Je ne parle Francais" y "Je voudrais une kilo du pomme du terre, s'il vous plais", ninguno de los cuales es muy útil, y probablemente horriblemente escrito :-) Lo has hecho mejor trabajo de lo que podría en una situación similar. – paxdiablo

+13

Tu inglés es bastante bueno en realidad. Ha logrado hacer una pregunta que está mejor redactada y mejor estructurada que muchas personas que visitan este sitio y hablan inglés como su primer idioma. – mdm

+0

Además, ¿qué ocurre si te conectas con un cliente FTP habitual al sitio? ¿Puedes descargar el archivo? Parece que hay un error de conectividad entre usted y el servidor: su código se ve bien. ¿Qué pasa si apunta su código a un sitio FTP diferente (tal vez un servidor FTP local en su máquina)? ¿Falla entonces? – mdm

Respuesta

2

Aquí hay un buen hilo de cosas para probar:

http://social.msdn.microsoft.com/Forums/en/ncl/thread/47634ec2-4d40-4d3f-b075-8cc92bfa2b24

Aumentar el tiempo de espera es probablemente una buena idea en lo más mínimo.

+0

. Voy a probar esta solución. – Hariboox

+0

No sé si algo solucionó ese problema en particular, pero se parece a lo que estás experimentando. Se puede complicar con archivos grandes. – ScottE

+0

Creo que estoy cerca de la solución ahora. deja ver mi nueva edición – Hariboox

12

Solo quiero fortalecer el diagnóstico de ScottE y ser más específico. El tiempo de espera es probablemente el problema.

O la implementación .Net de FtpWebRequest es errónea o the MSDN document tiene un error tipográfico, el valor predeterminado de FtpWebRequest.Timeout no es -1 (infinito). Es 100000 (100 segundos).

Además, hay otro problema de tiempo de espera. Algunas pruebas han demostrado que responseStream siempre tiene un valor de tiempo de espera de 300000 (300 segundos). No sé cómo se asigna este valor. De todos modos, este valor debe modificarse para acomodar archivos grandes.

En resumen, la solución es establecer FtpWebRequest.Timeout y Stream.Timeout en un valor suficientemente grande.

+0

Puedo confirmar que la documentación de FtpWebRequest.Timeout es incorrecta. @Hong tiene razón ... son 100 segundos. –

0

Esto podría ser un síntoma de un problema con la configuración de su Firewall de Windows. Desactivé el "Servicio de puerta de enlace de capa de aplicación" en la interfaz de "servicios".

Esta discusión tiene una gran cantidad de información:

http://forum.parallels.com/pda/index.php/t-57966.html

+1

El enlace está muerto. –

Cuestiones relacionadas