FTP上传文件,报“系统错误”

时间:2024-03-09 14:54:13

最近通过FTP上传文件遇到了报“系统错误”异常。 

一、代码示例

1、FTP上传代码

public Boolean ftpUpload(string filePath, string fileContent, string fileName, Boolean b_isFtpBackup)
    {
        b_ftpRet = true;
        if (s_isFtp.Equals("1"))
        {
            FileUtil.getInstance().backupLog("ftpUpload start", IniUtil.getInstance().b_debug);
            FileInfo fileInf = new FileInfo(filePath);
            string uri = ftpURI + fileInf.Name;
            FileUtil.getInstance().backupLog("根据uri创建FtpWebRequest对象" + uri, IniUtil.getInstance().b_debug);
            // 根据uri创建FtpWebRequest对象
            FtpWebRequest reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri(uri));
            if (ftpUserID != null)
            {
                reqFTP.Credentials = new NetworkCredential(ftpUserID, ftpPassword);
            }
            FileUtil.getInstance().backupLog("根据uri创建FtpWebRequest对象完毕", IniUtil.getInstance().b_debug);
            // 默认为true,连接不会被关闭  
            // 在一个命令之后被执行  
            reqFTP.KeepAlive = false;
            //指定执行什么命令  
            reqFTP.Method = WebRequestMethods.Ftp.UploadFile;
            // 指定数据传输类型
            reqFTP.UseBinary = true;
            reqFTP.UsePassive = false;
            // 上传文件时通知服务器文件的大小  
            reqFTP.ContentLength = fileInf.Length;
            reqFTP.Timeout = 30000;
            // 缓冲大小设置为2kb 
            int buffLength = 2048;
            byte[] buff = new byte[buffLength];
            int contentLen;
            FileStream fs = null;
            Stream strm = null;
            try
            {
                FileUtil.getInstance().backupLog("111111111111111", IniUtil.getInstance().b_debug);
                // 打开一个文件流 (System.IO.FileStream) 去读上传的文件  
                fs = fileInf.OpenRead();
                FileUtil.getInstance().backupLog("22222222222", IniUtil.getInstance().b_debug);
                // 把上传的文件写入流
                strm = reqFTP.GetRequestStream();
                FileUtil.getInstance().backupLog("3333333333333", IniUtil.getInstance().b_debug);
                // 每次读文件流的2kb  
                contentLen = fs.Read(buff, 0, buffLength);
                FileUtil.getInstance().backupLog("4444444444444444", IniUtil.getInstance().b_debug);
                // 流内容没有结束
                while (contentLen != 0)
                {
                    // 把内容从file stream 写入 upload stream  
                    strm.Write(buff, 0, contentLen);
                    FileUtil.getInstance().backupLog("555555555555555", IniUtil.getInstance().b_debug);
                    contentLen = fs.Read(buff, 0, buffLength);
                }
                if (b_isFtpBackup)
                {
                    FileUtil.instance.Log(filePath + "--上传成功!");
                }
                else
                {
                    if (MainForm.instance.bufferFTPBtn.Enabled)
                    {
                        FTPStateChange("缓存文件上传中...");
                        FileUtil.getInstance().backupLog("缓存文件上传中...");
                        BufferFTPChange(false);
                    }
                }
            }
            catch (Exception ex)
            {
                if (ftpBufferUploadRuuning)
                {
                    FTPStateChange("FTP连接失败!");
                    FileUtil.getInstance().backupLog("FTP连接失败!");
                    BufferFTPChange(true);
                }
                b_ftpRet = false;
                if (b_isFtpBackup)
                {
                    FileUtil.instance.Log(filePath + "--上传失败!");
                }
                FileUtil.instance.backupLog("Ftphelper Upload Error --> " + ex.Message);
                if (IniUtil.getInstance().isBackup.Equals("1") && b_isFtpBackup)
                {
                    FileUtil.getInstance().WriteFile(FileUtil.getInstance().ftpBufferPath + "\\" + fileName, fileContent, null, FileMode.Create);
                }
            }
            finally
            {
                // 关闭两个流 
                try
                {
                    if (strm != null)
                    {
                        strm.Close();
                    }
                }
                catch (Exception e)
                {
                    FileUtil.instance.backupLog("strm.Close() exception," + e.Message);
                }
                try
                {
                    if (fs != null)
                    {
                        fs.Close();
                    }
                }
                catch (Exception e)
                {
                    FileUtil.instance.backupLog("fs.Close() exception," + e.Message);
                }
            }
        }
        return b_ftpRet;
    }
}

2、检测FTP是否可用代码

public Boolean CheckFtp()
{
	Boolean ret = true;
	try {
        FileUtil.getInstance().Log("checkftp start," + ftpURI);
        FtpWebRequest reqFTP;
        // 根据uri创建FtpWebRequest对象
        FileUtil.getInstance().Log("根据uri创建FtpWebRequest对象...");
        reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri(ftpURI));
        FileUtil.getInstance().Log("获取ListDirectory...");
        reqFTP.Method = WebRequestMethods.Ftp.ListDirectory;
        FileUtil.getInstance().Log("userID,password登录...");
        reqFTP.UseBinary = true;
		reqFTP.Credentials = new NetworkCredential(ftpUserID, ftpPassword);
        FileUtil.getInstance().Log("登录后等待response...");
        FtpWebResponse response = (FtpWebResponse)reqFTP.GetResponse();
        FileUtil.getInstance().Log("获取response成功,ftp连接成功!");
    } catch (Exception e) {
		if(!b_ftpRet){
			FileUtil.instance.Log("CheckFtp Exception:" + e.Message);
		}
		ret = false;
	}
	return ret;
}

测试FTP连接居然用了10秒,而我的FTPtimeout设置的是2秒,故失败,但是为什么这么慢呢?

3、FTP工具测试

 

二、原因分析

1、FtpWebRequest.KeepAlive

如果不应销毁到服务器的连接,则为 true;否则为 false。 默认值是 true

2、FtpWebRequest.UseBinary

true,指示服务器要传输的是二进制数据;false,指示数据为文本。 默认值是 true

3、FtpWebRequest.UsePassive

(1)默认值:true,被动模式

PASV(被动)方式的连接过程是:客户端向服务器的FTP端口(默认是21)发送连接请求,服务器接受连接,建立一条命令链路。 当需要传送数据时, 服务器在命令链路上用PASV命令告诉客户端:“我打开了***X端口,你过来连接我”。于是客户端向服务器的***X端口发送连接请求,建立一条数据链 路来传送数据。

(2)UsePassive=false,主动模式

PORT(主动)方式的连接过程是:客户端向服务器的FTP端口(默认是21)发送连接请求,服务器接受连接,建立一条命令链路。 当需要传送数据时, 客户端在命令链路上用PORT命令告诉服务器:“我打开了***X端口,你过来连接我”。于是服务器从20端口向客户端的***X端口发送连接请求,建立 一条数据链路来传送数据。 

(3)优缺点

主动FTP对FTP服务器的管理有利,但对客户端的管理不利。因为FTP服务器企图与客户端的高位随机端口建立连接,而这个端口很有可能被客户端的防火墙阻塞掉。被动FTP对FTP客户端的管理有利,但对服务器端的管理不利。因为客户端要与服务器端建立两个连接,其中一个连到一个高位随机端口,而这个端口很有可能被服务器端的防火墙阻塞掉。

感觉和这个没啥关系啊。

4、此时,灵光乍现,reqFTP.Timeout = 2000;

FTP上传超时2秒,也就是说2秒上传失败的话,就不传了,但是测试FTP都需要10秒,故失败,系统错误,传不上去。

索性改为20秒算了,开心的是性能客户不考虑,告诉我能传上去就行了,真的是良心客户啊,但是还是没找到根本原因,我感觉是FTP服务端设置了什么东西,不让客户端传的太频繁,防止服务端由于客户端太多,上传太频繁而宕机。

由于工作繁忙,先到这,以后出现问题,再重构吧。