重复调用后,FtpWebRequest会抛出以下异常:"底层连接已关闭:接收时发生意外错误。"

时间:2017-09-04 20:17:58

标签: c# exception ftp ftpwebrequest

我的目标是编写一个程序,从ftp服务器下载一个包含所有文件和嵌套目录的目录。所以要做到这一点,我需要两个功能:1)列出目录中的所有文件/目录,2)下载特定文件。然后我可以递归遍历目录并在我的本地计算机上重新创建它。

因此,让我向您展示我正在使用的代码。

1)遗憾的是,对于目录遍历,我无法找到使用FtpWebRequest可靠地完成目标的方法。因此,在我的实施中,我使用了两个ftp命令ListDirectoryListDirectoryDetails。第一个给我文件/目录名,第二个用于确定它是文件还是目录。 (遗憾的是,我无法找到一种可靠的方法来解析ListDirectoryDetails返回的输出 - 每个人似乎都在使用他们自己的正则表达式,并且更糟糕的是,似乎不同的ftp服务器可能会报告它以不同的方式。)

//Example of strURI = "ftp://server123.domain.com/%2F/public_html"
FtpWebRequest ftpRequest1 = (FtpWebRequest)WebRequest.Create(strURI);
ftpRequest1.EnableSsl = true;   //Use TLS!
ftpRequest1.Credentials = credentials;
ftpRequest1.KeepAlive = kbKeepAlive;
ftpRequest1.Timeout = knFtpTimeout;

ftpRequest1.Method = WebRequestMethods.Ftp.ListDirectoryDetails;

using (FtpWebResponse response1 = (FtpWebResponse)ftpRequest1.GetResponse())
{
    FtpWebRequest ftpRequest2 = (FtpWebRequest)WebRequest.Create(strURI);
    ftpRequest2.EnableSsl = true;   //Use TLS!
    ftpRequest2.Credentials = credentials;
    ftpRequest2.KeepAlive = kbKeepAlive;
    ftpRequest2.Timeout = knFtpTimeout;

    ftpRequest2.Method = WebRequestMethods.Ftp.ListDirectory;

    using (StreamReader streamReader = new StreamReader(response1.GetResponseStream()))
    {
        List<string> arrFullDirList = new List<string>();

        for (; ; )
        {
            string line = streamReader.ReadLine();
            if (string.IsNullOrEmpty(line))
                break;

            arrFullDirList.Add(line);
        }

        using (FtpWebResponse response2 = (FtpWebResponse)ftpRequest2.GetResponse())
        {
            using (StreamReader streamReader2 = new StreamReader(response2.GetResponseStream()))
            {
                List<string> arrDirNamesList = new List<string>();

                for (; ; )
                {
                    string line = streamReader2.ReadLine();
                    if (string.IsNullOrEmpty(line))
                        break;

                    arrDirNamesList.Add(line);
                }

                //Then analyze two arrays
                if (arrFullDirList.Count == arrDirNamesList.Count)
                {
                    //If the first char in `arrFullDirList` item is 'd' then
                    //it's a directory. If it's '-' then it's a file...
                }
            }

            response2.Close();
        }
    }

    response1.Close();
}

2)对于文件下载,我使用以下代码:

//Query size of the file to be downloaded
//Example of strURI = "ftp://server123.domain.com/%2F/public_html/.htaccess"
FtpWebRequest requestSz = (FtpWebRequest)WebRequest.Create(strURI);
requestSz.EnableSsl = true; //Use TLS!
requestSz.Credentials = credentials;
requestSz.UseBinary = true;
requestSz.Method = WebRequestMethods.Ftp.GetFileSize;
requestSz.Timeout = knFtpTimeout;

using (FtpWebResponse responseSize = (FtpWebResponse)requestSz.GetResponse())
{
    //File size
    long uiFileSize = responseSize.ContentLength;

    //Download file request
    FtpWebRequest request = (FtpWebRequest)WebRequest.Create(strURI);
    request.EnableSsl = true;   //Use TLS!
    request.Credentials = credentials;
    request.UseBinary = true;
    request.Timeout = knFtpTimeout;

    request.Method = WebRequestMethods.Ftp.DownloadFile;

    using (FtpWebResponse response = (FtpWebResponse)request.GetResponse())
    {
        using (Stream ftpStream = response.GetResponseStream())
        {
            const int kBufferLength = 1024;
            byte[] buffer = new byte[kBufferLength];

            using (FileStream streamFile = File.Create(strLocalFilePath))
            {
                for (long uiProcessedSize = 0; ; )
                {
                    int ncbRead = ftpStream.Read(buffer, 0, kBufferLength);
                    if (ncbRead == 0)
                    {
                        break;
                    }

                    streamFile.Write(buffer, 0, ncbRead);

                    uiProcessedSize += ncbRead;

                    double fProgress = (double)uiProcessedSize / (double)uiFileSize;
                    fProgress *= 100.0;

                    //Show download progress for a user ...
                }
            }
        }

        response.Close();
    }

    responseSize.Close();
}

最后我使用以下全局变量:

    const bool kbKeepAlive = true;
    const int knFtpTimeout = -1;

    NetworkCredential credentials = new NetworkCredential("user_name", "password");

所以我使用这种方法尝试从(付费)共享网络托管服务器下载我的小网站文件。这种方式非常奇怪:

  • 如果我设置kbKeepAlive = true,则下载速度会快得多,但是在某个可预测的时间点,FtpWebResponse次调用之一会抛出此异常:
  

基础连接已关闭:发生意外错误   收到。

  • 如果我设置kbKeepAlive = false,则下载速度较慢,并且进度远远超过上述示例,但在某些时候它也会抛出同样的异常。

这个过程是可重复的,感觉几乎就像是一个计数器,或者一些资源被耗尽,最终耗尽导致这个错误。

所以我做了一些搜索。这个例外有很多点击,但不幸的是,没有一个修复建议似乎适合我:

a)某人suggested increasing the timeout。好吧,我用我的knFtpTimeout = -1完全删除了它,它没有任何区别。

b)然后有人suggested to enable network tracing并检查日志。所以我也这样做了。这是我在日志中得到的内容。我不确定它是否回答任何问题:

(日志本身非常大,但这里结束了。我编辑了实际的ftp服务器URL。)

[Subject]
  CN=*.domain.com, OU=PositiveSSL Wildcard, OU=Domain Control Validated
  Simple Name: *.domain.com
  DNS Name: domain.com

[Issuer]
  CN=COMODO RSA Domain Validation Secure Server CA, O=COMODO CA Limited, L=Salford, S=Greater Manchester, C=GB
  Simple Name: COMODO RSA Domain Validation Secure Server CA
  DNS Name: COMODO RSA Domain Validation Secure Server CA

[Serial Number]
  00F61110ACEE4BF307C442973F3B842A2E

[Not Before]
  2/3/2015 4:00:00 PM

[Not After]
  3/7/2018 3:59:59 PM

[Thumbprint]
  F429DCB7B8181F0236432890C3E10D99719AC698

[Signature Algorithm]
  sha256RSA(1.2.840.113549.1.1.11)

[Public Key]
  Algorithm: RSA
  Length: 2048
  Key Blob: 30 82 01 0a 02 82 01 01 00 d1 68 8c 67 75 9a f2 93 b1 25 95 2d 43 32 d6 83 18 07 09 ba 1a 2a d3 b3 b6 09 75 eb 92 05 9d 41 ab 38 ad a7 af 2a d1 5e f4 02 21 b0 d5 8b fe 54 17 da 90 2f c2 06 c7 6a 8b 57 fb 1b f9 4d 25 c4 9d b0 7c 31 94 19 ee 27 9c 81 ed b1 01 ba 7e 06 0f af d8 9a 81 94 25 ....
System.Net Information: 0 : [12064] SecureChannel#32368095 - Remote certificate was verified as valid by the user.
System.Net Information: 0 : [12064] ProcessAuthentication(Protocol=Tls, Cipher=Aes128 128 bit strength, Hash=Sha1 160 bit strength, Key Exchange=44550 256 bit strength).
System.Net Error: 0 : [12064] Decrypt failed with error 0X90317.
System.Net Information: 0 : [12064] FtpControlStream#11318800 - Received response [226-File successfully transferred
226 0.000 seconds (measured here), 0.58 Mbytes per second]
System.Net Information: 0 : [12064] FtpWebRequest#21940722::(Releasing FTP connection#11318800.)
System.Net Information: 0 : [12064] FtpWebRequest#41130254::.ctor(ftp://server123.domain.com///public_html/ctc)
System.Net Information: 0 : [12064] FtpWebRequest#41130254::GetResponse(Method=LIST.)
System.Net Information: 0 : [12064] Associating FtpWebRequest#41130254 with FtpControlStream#11318800
System.Net Information: 0 : [12064] FtpControlStream#11318800 - Sending command [CWD //public_html]
System.Net Information: 0 : [12064] FtpControlStream#11318800 - Received response [250 OK. Current directory is /public_html]
System.Net Information: 0 : [12064] FtpControlStream#11318800 - Sending command [PASV]
System.Net Information: 0 : [12064] FtpControlStream#11318800 - Received response [227 Entering Passive Mode (192,64,117,187,47,58)]
System.Net Information: 0 : [12064] FtpControlStream#11318800 - Sending command [LIST ctc]
System.Net Information: 0 : [12064] FtpWebRequest#41130254::(Releasing FTP connection#11318800.)
System.Net Error: 0 : [12064] Exception in FtpWebRequest#41130254::GetResponse - The underlying connection was closed: An unexpected error occurred on a receive..
   at System.Net.FtpWebRequest.SyncRequestCallback(Object obj)
   at System.Net.FtpWebRequest.RequestCallback(Object obj)
   at System.Net.CommandStream.Dispose(Boolean disposing)
   at System.IO.Stream.Close()
   at System.IO.Stream.Dispose()
   at System.Net.ConnectionPool.Destroy(PooledStream pooledStream)
   at System.Net.ConnectionPool.PutConnection(PooledStream pooledStream, Object owningObject, Int32 creationTimeout, Boolean canReuse)
   at System.Net.FtpWebRequest.FinishRequestStage(RequestStage stage)
   at System.Net.FtpWebRequest.GetResponse()
System.Net Information: 0 : [12064] FtpControlStream#33675143 - Received response [226-Options: -a 
226 133 matches total]
System.Net Information: 0 : [12064] FtpWebRequest#21454193::(Releasing FTP connection#33675143.)

所以我知道我做错了什么?

0 个答案:

没有答案