Базовое соединение было закрыто: при приеме произошла непредвиденная ошибка.

Я здесь, потому что у меня возникла проблема при загрузке некоторых файлов по ftp-протоколу. Это странно, потому что это происходит время от времени и даже для одного и того же файла.

Просто точность: я загружаю очень большие файлы (от 500 Mo до 30 Go)

Вот какие исключения возвращаются моей функцией: (извините, это по-французски)

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

Метод существует:

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.

Второе исключение вызвано этой частью кода метода Download:

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

Я продолжаю свои исследования, но кажется, что гипотеза "timeout pb" является наиболее последовательной. Я попробую с большим значением тайм-аута сегодня вечером.


person Hariboox    schedule 10.06.2011    source источник
comment
Не извиняйся. Единственный французский, который я помню, это Je ne parle Francais и Je voudrais une kilo du pomme du terre, s'il vous plais, ни один из которых не очень полезен и, вероятно, написан ужасно :-) Вы сделали лучше, чем я мог в аналогичной ситуации.   -  person paxdiablo    schedule 10.06.2011
comment
Ваш английский довольно хорош на самом деле. Вам удалось задать вопрос, который лучше сформулирован и лучше структурирован, чем многие люди, которые посещают этот сайт и говорят на английском как на родном языке.   -  person mdm    schedule 10.06.2011
comment
Кроме того, что произойдет, если вы подключитесь к сайту с помощью обычного FTP-клиента? Вы можете скачать файл? Похоже, что между вами и сервером возникла ошибка подключения — ваш код выглядит нормально. А если вы укажете свой код на другой FTP-сайт (возможно, на локальный FTP-сервер на вашем компьютере)? Тогда не получится?   -  person mdm    schedule 10.06.2011
comment
Возможно, сервер закрывает соединение, но только иногда, возможно, ваша сеть ненадежна.   -  person Jodrell    schedule 10.06.2011
comment
@paxdiablo Единственный французский, который я помню со школы, это une biere s'il vous plait и ou est le Toilette. Оба бесценные члены моего многоязычного набора инструментов. Больше беспокоит то, что я почти ничего не помню из этого, но ZX-Spectrum BASIC и интимные подробности Apple IIcx навсегда укоренились в какой-то части моего мозга.   -  person mdm    schedule 10.06.2011
comment
biere и Toilette мгновенно узнаваемы для всех, кто имеет опыт работы с обоими концами этого конкретного процесса :-)   -  person paxdiablo    schedule 10.06.2011
comment
@mdm: сложно протестировать локально, потому что все файлы расположены на удаленном сервере, и если я хочу протестировать на своем компьютере, мне нужно сначала загрузить файлы, но загрузка 10 Go или 20 Go занимает так много времени ... и я не уверен, воспроизведет ли используемый файл исключение. :(. Кстати, я заметил, что Исключения возникают только на очень больших файлах (› 5 Go), но не всегда.   -  person Hariboox    schedule 10.06.2011
comment
@Hariboox: Похоже, что это тайм-аут, как указано в ссылке, опубликованной ScottE. Возможно, стоит просто запустить ваш FTP-клиент и попытаться загрузить файл — это, по крайней мере, скажет вам, является ли это проблемой с вашим кодом или проблемой с сервером, и вдвое сократит объем расследования, которое вам придется сделать.   -  person mdm    schedule 10.06.2011
comment
@mdm: Хорошо, я попытаюсь загрузить с помощью FileZilla, но я почти уверен, что с сервером проблем нет. но поживем-увидим :)   -  person Hariboox    schedule 10.06.2011
comment
@Hariboox, вы также можете создать свой собственный файл 5G для локального тестирования вместо загрузки. Маловероятно, что контент вызывает проблемы, но я не исключаю этого полностью :-)   -  person paxdiablo    schedule 10.06.2011
comment
@paxdiablo: да, конечно ^^. Но я хочу проверить это на исходных файлах, потому что я не совсем уверен, что это не их содержимое вызывает эти исключения... Ну, это было бы странно, но...   -  person Hariboox    schedule 10.06.2011
comment
Вы смотрели на временную обработку ошибок? Я бы, возможно, добавил политику повторных попыток, которая обычно решает проблемы с SQL-соединением.   -  person Christo    schedule 29.10.2012


Ответы (4)


Просто хочу усилить диагноз Скотта и быть более конкретным. Скорее всего, дело в тайм-ауте.

Либо реализация .Net FtpWebRequest ошибочна, либо документ MSDN содержит опечатку, значение FtpWebRequest.Timeout по умолчанию не равно -1 (бесконечно). Это 100000 (100 секунд).

Кроме того, есть еще одна проблема тайм-аута. Несколько тестов показали, что значение тайм-аута responseStream всегда равно 300000 (300 секунд). Я не знаю, как присваивается это значение. В любом случае, это значение необходимо изменить для размещения больших файлов.

Таким образом, решение состоит в том, чтобы установить для FtpWebRequest.Timeout и Stream.Timeout достаточно большое значение.

person Hong    schedule 23.11.2011
comment
Я могу подтвердить, что документация FtpWebRequest.Timeout неверна. @ Хонг прав... это 100 секунд. - person Mike L; 12.02.2013

Вот хорошая тема, чтобы попробовать:

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

Увеличение тайм-аута, вероятно, является хорошей идеей.

person ScottE    schedule 10.06.2011
comment
я собираюсь попробовать это решение. - person Hariboox; 10.06.2011
comment
Я не знаю, решило ли что-нибудь эту конкретную проблему, но это похоже на то, что вы испытываете. Это может быть сложно с большими файлами. - person ScottE; 10.06.2011
comment
@Hariboox - я рекомендую вам использовать конструкцию «using» для автоматического вызова методов dispose для любого метода, реализующего IDisposable. Это помогает предотвратить утечки или блокировки. - person ScottE; 10.06.2011

Это может быть признаком проблемы с настройками брандмауэра Windows. Отключение «Службы шлюза прикладного уровня» в интерфейсе «службы» исправило это для меня.

В этой теме много информации:

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

person JerSchneid    schedule 29.10.2012

Попробуйте установить:

request.EnableSsl = true
person Pradhan Salian    schedule 29.10.2018