6

我有一个接受 XML 并最终根据 XML 中的信息上传文件的 API。上传是按计划进行的(也来自 XML),我已经测试了它周围的所有东西,并且知道它可以工作。

我在每个时间周期中尝试上传的第一个文件大约有 40% 的时间出现错误(时间周期 = 某些文件为 45 分钟,其他文件为 30 分钟)。

这是我的上传代码:

try {
    LoggerFTP.Log("Uploading file: " + filename, false);

    // Create the request.
    FtpWebRequest request = (FtpWebRequest)WebRequest.Create(appSettingsFTP.ftpUrl + @"/" + filename);
    request.Method = WebRequestMethods.Ftp.UploadFile;
    request.Timeout = 6000000; //set to 100 minutes
    //request.Timeout = -1; //set to infinite

    // Add the login credentials.
    request.Credentials = new NetworkCredential(appSettingsFTP.ftpLogin, appSettingsFTP.ftpPassword);

    // Grab the file contents.
    StreamReader sourceStream = new StreamReader(appSettingsFTP.uploadFileDirectory + filename);
    byte[] fileContents = Encoding.UTF8.GetBytes(sourceStream.ReadToEnd());
    sourceStream.Close();
    request.ContentLength = fileContents.Length;

    // Copy the file contents to the outgoing stream.
    Stream requestStream = request.GetRequestStream();
    requestStream.Write(fileContents, 0, fileContents.Length);
    requestStream.Close();

    FtpWebResponse response = (FtpWebResponse)request.GetResponse();
    //Logger.Log(filename.ToString() + " " + "Upload Complete, Status: " + response.StatusCode + " " + response.StatusDescription, false);
    //Took response.StatusDescription out because it appears to be creating extra line feeds.
    LoggerFTP.Log(filename.ToString() + " " + "Upload Complete, Status: " + response.StatusCode, false);
}
catch (Exception ex) {
    LoggerFTP.Log(ex.ToString(), false);
}

我已经研究了这个问题,并在网上看到了一些关于它可能是速度的东西。就像,有一个超时。但是我将 FtpWebRequest 的超时设置为 100 分钟,所以不可能是这样吗?我不知道。这也是作为服务运行的,因此很难测试代码的这方面。

这是在我的记录器(e.ToString)中记录的异常:

System.Net.WebException: System error. ---> System.Net.InternalException: System error.
   at System.Net.PooledStream.PrePush(Object expectedOwner)
   at System.Net.ConnectionPool.PutConnection(PooledStream pooledStream, Object owningObject, Int32 creationTimeout, Boolean canReuse)
   at System.Net.FtpWebRequest.FinishRequestStage(RequestStage stage)
   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.AttemptedRecovery(Exception e)
   at System.Net.FtpWebRequest.SubmitRequest(Boolean async)
   --- End of inner exception stack trace ---
   at System.Net.FtpWebRequest.GetRequestStream()
   at CPMainSpringAPIExportsSC.UploadFTP.FTPUploadMethod(String viewname, String filename)
4

2 回答 2

5

我在尝试通过 SSL 进行 FTP 的 SSIS 包中得到完全相同的堆栈跟踪。如果没有 SSL,它就可以很好地工作,但是一旦我启用 SSL,它就会爆炸。

    System.Net.WebException: System error. --->
    System.Net.InternalException: System error.    at
    System.Net.PooledStream.PrePush(Object expectedOwner)    at
    System.Net.ConnectionPool.PutConnection(PooledStream pooledStream, Object owningObject, Int32 creationTimeout, Boolean canReuse)    at
    System.Net.FtpWebRequest.FinishRequestStage(RequestStage stage)    at
    System.Net.FtpWebRequest.SyncRequestCallback(Object obj)    at
    System.IO.Stream.Close()    at
    System.Net.ConnectionPool.Destroy(PooledStream pooledStream)    at
    System.Net.ConnectionPool.PutConnection(PooledStream pooledStream, Object owningObject, Int32 creationTimeout, Boolean canReuse)    at
    System.Net.FtpWebRequest.AttemptedRecovery(Exception e)    at
    System.Net.FtpWebRequest.SubmitRequest(Boolean async)
    --- End of inner exception stack trace ---    at
    System.Net.FtpWebRequest.CheckError()    at
    System.Net.FtpWebRequest.GetRequestStream()    at
    ST_0ff7348de65a468bb358ab0206e3721f.ScriptMain.Main() in c:\Users\Stephens\AppData\Local\Temp\Vsta\e664c8a71bb647ff9e9dc6ac32d7b615\ScriptMain.cs:line 155 at 
    System.Net.FtpWebRequest.CheckError()    at
    System.Net.FtpWebRequest.GetRequestStream()    at
    ST_0ff7348de65a468bb358ab0206e3721f.ScriptMain.Main() in c:\Users\Stephens\AppData\Local\Temp\Vsta\e664c8a71bb647ff9e9dc6ac32d7b615\ScriptMain.cs:line 155

因为这个错误太笼统了,所以我决定查看 .NET 源代码,看看是否能找到关于什么是破坏的线索。如果你去这里:

http://labs.developerfusion.co.uk/SourceViewer/browse.aspx?assembly=SSCLI&namespace=System.Net#{%22pageClientState%22%3A%22type-2844%2Ccsharp%22}

并跳到第 281 行,您将看到内部 void PrePush(object expectedOwner) 的定义,这是发生异常时正在执行的操作。这是它的样子:

    internal void PrePush(object expectedOwner)
    {
        lock (this) {
            //3 // The following tests are retail assertions of things we can't allow to happen.
            if (null == expectedOwner) {
                if (null != m_Owner && null != m_Owner.Target)
                    throw new InternalException();
                // new unpooled object has an owner
            }
            else {
                if (null == m_Owner || m_Owner.Target != expectedOwner)
                    throw new InternalException();
                // unpooled object has incorrect owner
            }

            m_PooledCount++;

            if (1 != m_PooledCount)
                throw new InternalException();
            // pushing object onto stack a second time
            if (null != m_Owner)
                m_Owner.Target = null;
        }
    }

最终我发现 FtpWebRequest 只支持显式 FTP(端口 21)而不支持隐式 FTP(端口 990)。此处明确说明了这一点:

.NET FtpWebRequest 是否同时支持隐式 (FTPS) 和显式 (FTPES)?

无论如何,就我而言,这是一个防火墙问题。最初我们配置为隐式 FTP,即端口 989、990、49152-65535(根据供应商的技术人员)。我咨询了我的网络人员,我们为明确开放了 20、21、989、990 和 40000-655535 端口,之后一切都像冠军一样工作。

但是,在您的情况下,您似乎对连接池感到兴奋。这里有一篇关于这个主题的好帖子:

如何提高 FtpWebRequest 的性能?

您可能想看看如何设置连接池,看看是否可以取得一些进展。希望这可以帮助!

问候,

斯图尔特

于 2015-05-20T23:38:47.673 回答
0

我知道这是一个老话题,但对于任何有同样问题的人来说,缺少的代码是:

            request.EnableSsl = false;
于 2017-05-31T14:13:01.680 回答