设为首页 收藏本站
查看: 1267|回复: 0

Discuz!NT中远程附件的功能实现[FTP协议]

[复制链接]

尚未签到

发表于 2015-5-30 07:27:30 | 显示全部楼层 |阅读模式
  大约在去年的12月份,我们开始着手设计和开发这项功能,而该项功能主要是解决类似于一些
  帖子附件(图片或文件)访问比较频繁,同时附件的体积又比较大,从而造成对主站服务器访问压
  力过大的问题。而实现了该项功能之后,在一些合作伙伴的站点上使用了一段时间,发现该功能明
  显的降低了主站服务器的负载,使其可以节省更多的资源(cpu,内存等) 用于处理用户的其它访问
  请求。


  下面就简要介绍一下该功能的一些实现细节, 该项功能所实现的流程如下图所示:
  
DSC0000.jpg
      而主要的核心就是采用FTP协议上传附件到远程的服务器上,这样当用户点开网页或进行附件下
  载时,就会将链接指向远程的FTP服务上(该服务器要支持HTTP协议访问其资源)。而这个类的原
  型链接如下:


     http://www.csharphelp.com/archives/archive9.html
   
  本人在其基础上修改了该类在DEBUG模式下上传文件过程中的BUG,同时翻译了其注释内容。大
  家可在dicuz.common.dll(discuz!nt 2.1以后的版块)的中找到该类(使用Reflector)。
  
  下面是其核心代码(您可在下个开源版本中获取该类的全部代码):
  

DSC0001.gif DSC0002.gif Code
/**////
DSC0003.gif     /// FTP类
DSC0004.gif     ///
DSC0005.gif     public class FTP
    DSC0006.gif {
DSC0007.gif DSC0008.gif         变量声明#region 变量声明

        /**////
        /// 服务器连接地址
DSC0009.gif         ///
        public string server;

        /**////
        /// 登陆帐号
        ///
        public string user;

        /**////
        /// 登陆口令
        ///
        public string pass;

        /**////
        /// 端口号
        ///
        public int port;

        /**////
        /// 无响应时间(FTP在指定时间内无响应)
        ///
        public int timeout;

        /**////
        /// 服务器错误状态信息
        ///
        public string errormessage;

   
        /**////
        /// 服务器状态返回信息
        ///
        private string messages;

        /**////
        /// 服务器的响应信息
        ///
        private string responseStr;

        /**////
        /// 链接模式(主动或被动,默认为被动)
        ///
        private bool passive_mode;        

        /**////
        /// 上传或下载信息字节数
        ///
        private long bytes_total;

        /**////
        /// 上传或下载的文件大小
        ///
        private long file_size;

        /**////
        /// 主套接字
        ///
        private Socket main_sock;

        /**////
        /// 要链接的网络地址终结点
        ///
        private IPEndPoint main_ipEndPoint;

        /**////
        /// 侦听套接字
        ///
        private Socket listening_sock;

        /**////
        /// 数据套接字
        ///
        private Socket data_sock;

        /**////
        /// 要链接的网络数据地址终结点
        ///
        private IPEndPoint data_ipEndPoint;

        /**////
        /// 用于上传或下载的文件流对象
        ///
        private FileStream file;

        /**////
        /// 与FTP服务器交互的状态值
        ///
        private int response;

        /**////
        /// 读取并保存当前命令执行后从FTP服务器端返回的数据信息
        ///
        private string bucket;

        #endregion

        构造函数#region 构造函数

        /**////
        /// 构造函数
        ///
        public FTP()
        {
            server = null;
            user = null;
            pass = null;
            port = 21;
            passive_mode = true;        
            main_sock = null;
            main_ipEndPoint = null;
            listening_sock = null;
            data_sock = null;
            data_ipEndPoint = null;
            file = null;
            bucket = "";
            bytes_total = 0;
            timeout = 10000;    //无响应时间为10秒
            messages = "";
            errormessage = "";
        }

        /**////
        /// 构造函数
        ///
        /// 服务器IP或名称
        /// 登陆帐号
        /// 登陆口令
        public FTP(string server, string user, string pass)
        {
            this.server = server;
            this.user = user;
            this.pass = pass;
            port = 21;
            passive_mode = true;   
            main_sock = null;
            main_ipEndPoint = null;
            listening_sock = null;
            data_sock = null;
            data_ipEndPoint = null;
            file = null;
            bucket = "";
            bytes_total = 0;
            timeout = 10000;    //无响应时间为10秒
            messages = "";
            errormessage = "";
        }
      
        /**////
        /// 构造函数
        ///
        /// 服务器IP或名称
        /// 端口号
        /// 登陆帐号
        /// 登陆口令
        public FTP(string server, int port, string user, string pass)
        {
            this.server = server;
            this.user = user;
            this.pass = pass;
            this.port = port;
            passive_mode = true;   
            main_sock = null;
            main_ipEndPoint = null;
            listening_sock = null;
            data_sock = null;
            data_ipEndPoint = null;
            file = null;
            bucket = "";
            bytes_total = 0;
            timeout = 10000;    //无响应时间为10秒
            messages = "";
            errormessage = "";
        }


        /**////
        /// 构造函数
        ///
        /// 服务器IP或名称
        /// 端口号
        /// 登陆帐号
        /// 登陆口令
        /// 链接方式
        public FTP(string server, int port, string user, string pass, int mode)
        {
            this.server = server;
            this.user = user;
            this.pass = pass;
            this.port = port;
            passive_mode = mode  timeout)
                {
                    Disconnect();
                    errormessage += "Timed out waiting on server to respond.";
                    return;
                }
            }

            while (main_sock.Available > 0)
            {
                bytesgot = main_sock.Receive(bytes, 512, 0);
                bucket += Encoding.ASCII.GetString(bytes, 0, (int)bytesgot);
                System.Threading.Thread.Sleep(50);
            }
        }


        private string GetLineFromBucket()
        {
            int i;
            string buf = "";

            if ((i = bucket.IndexOf('\n')) < 0)
            {
                while (i < 0)
                {
                    FillBucket();
                    i = bucket.IndexOf('\n');
                }
            }

            buf = bucket.Substring(0, i);
            bucket = bucket.Substring(i + 1);

            return buf;
        }


        /**////
        /// 返回服务器端返回信息
        ///
        private void ReadResponse()
        {
            string buf;
            messages = "";

            while (true)
            {
                buf = GetLineFromBucket();

                if (Regex.Match(buf, "^[0-9]+ ").Success)
                {
                    responseStr = buf;
                    response = int.Parse(buf.Substring(0, 3));
                    break;
                }
                else
                    messages += Regex.Replace(buf, "^[0-9]+-", "") + "\n";
            }
        }


        /**////
        /// 打开数据套接字
        ///
        private void OpenDataSocket()
        {
            if (passive_mode)
            {
                string[] pasv;
                string server;
                int port;

                Connect();
                SendCommand("PASV");
                ReadResponse();
                if (response != 227)
                    Fail();

                try
                {
                    int i1, i2;

                    i1 = responseStr.IndexOf('(') + 1;
                    i2 = responseStr.IndexOf(')') - i1;
                    pasv = responseStr.Substring(i1, i2).Split(',');
                }
                catch (Exception)
                {
                    Disconnect();
                    errormessage += "Malformed PASV response: " + responseStr;
                    return ;
                }

                if (pasv.Length < 6)
                {
                    Disconnect();
                    errormessage += "Malformed PASV response: " + responseStr;
                    return ;
                }

                server = String.Format("{0}.{1}.{2}.{3}", pasv[0], pasv[1], pasv[2], pasv[3]);
                port = (int.Parse(pasv[4])  (timeout / 10))
                {
                    break;
                }
            }

            while (data_sock.Available > 0)
            {
                bytesgot = data_sock.Receive(bytes, bytes.Length, 0);
                file_list += Encoding.ASCII.GetString(bytes, 0, (int)bytesgot);
                System.Threading.Thread.Sleep(50);
            }

            CloseDataSocket();

            ReadResponse();
            if (response != 226)
                throw new Exception(responseStr);

            foreach (string f in file_list.Split('\n'))
            {
                if (f.Length > 0 && !Regex.Match(f, "^total").Success)
                    list.Add(f.Substring(0, f.Length - 1));
            }

            return list;
        }

        /**////
        /// 获取到文件名列表
        ///
        /// 返回文件名列表
        public ArrayList ListFiles()
        {
            ArrayList list = new ArrayList();

            foreach (string f in List())
            {
                if ((f.Length > 0))
                {
                    if ((f[0] != 'd') && (f.ToUpper().IndexOf("") < 0))
                        list.Add(f);
                }
            }

            return list;
        }

        /**////
        /// 获取路径列表
        ///
        /// 返回路径列表
        public ArrayList ListDirectories()
        {
            ArrayList list = new ArrayList();

            foreach (string f in List())
            {
                if (f.Length > 0)
                {
                    if ((f[0] == 'd') || (f.ToUpper().IndexOf("") >= 0))
                        list.Add(f);
                }
            }

            return list;
        }

        /**////
        /// 获取原始数据信息.
        ///
        /// 远程文件名
        /// 返回原始数据信息.
        public string GetFileDateRaw(string fileName)
        {
            Connect();

            SendCommand("MDTM " + fileName);
            ReadResponse();
            if (response != 213)
            {
                errormessage += responseStr;
                return "";
            }

            return (this.responseStr.Substring(4));
        }

        /**////
        /// 得到文件日期.
        ///
        /// 远程文件名
        /// 返回远程文件日期
        public DateTime GetFileDate(string fileName)
        {
            return ConvertFTPDateToDateTime(GetFileDateRaw(fileName));
        }

        private DateTime ConvertFTPDateToDateTime(string input)
        {
            if (input.Length < 14)
                throw new ArgumentException("Input Value for ConvertFTPDateToDateTime method was too short.");

            //YYYYMMDDhhmmss":
            int year = Convert.ToInt16(input.Substring(0, 4));
            int month = Convert.ToInt16(input.Substring(4, 2));
            int day = Convert.ToInt16(input.Substring(6, 2));
            int hour = Convert.ToInt16(input.Substring(8, 2));
            int min = Convert.ToInt16(input.Substring(10, 2));
            int sec = Convert.ToInt16(input.Substring(12, 2));

            return new DateTime(year, month, day, hour, min, sec);
        }

        /**////
        /// 获取FTP上的当前(工作)路径
        ///
        /// 返回FTP上的当前(工作)路径
        public string GetWorkingDirectory()
        {
            //PWD - 显示工作路径
            Connect();
            SendCommand("PWD");
            ReadResponse();

            if (response != 257)
            {
                errormessage += responseStr;
            }

            string pwd;
            try
            {
                pwd = responseStr.Substring(responseStr.IndexOf("\"", 0) + 1);//5);
                pwd = pwd.Substring(0, pwd.LastIndexOf("\""));
                pwd = pwd.Replace("\"\"", "\""); // 替换带引号的路径信息符号
            }
            catch (Exception ex)
            {
                errormessage += ex.Message;
                return null;
            }

            return pwd;
        }


        /**////
        /// 跳转服务器上的当前(工作)路径
        ///
        /// 要跳转的路径
        public bool ChangeDir(string path)
        {
            Connect();
            SendCommand("CWD " + path);
            ReadResponse();
            if (response != 250)
            {
                errormessage += responseStr;
                return false;
            }
            return true;
        }

        /**////
        /// 创建指定的目录
        ///
        /// 要创建的目录
        public void MakeDir(string dir)
        {
            Connect();
            SendCommand("MKD " + dir);
            ReadResponse();

            switch (response)
            {
                case 257:
                case 250:
                    break;
                default:
                    {
                        errormessage += responseStr;
                        break;
                    }
            }
        }

        /**////
        /// 移除FTP上的指定目录
        ///
        /// 要移除的目录
        public void RemoveDir(string dir)
        {
            Connect();
            SendCommand("RMD " + dir);
            ReadResponse();
            if (response != 250)
            {
                errormessage += responseStr;
                return; ;
            }
        }

        /**////
        /// 移除FTP上的指定文件
        ///
        /// 要移除的文件名称
        public void RemoveFile(string filename)
        {
            Connect();
            SendCommand("DELE " + filename);
            ReadResponse();
            if (response != 250)
            {
                errormessage += responseStr;
            }
        }

        /**////
        /// 重命名FTP上的文件
        ///
        /// 原文件名
        /// 新文件名
        public void RenameFile(string oldfilename, string newfilename)
        {
            Connect();
            SendCommand("RNFR " + oldfilename);
            ReadResponse();
            if (response != 350)
            {
                errormessage += responseStr;
            }
            else
            {
                SendCommand("RNTO " + newfilename);
                ReadResponse();
                if (response != 250)
                {
                    errormessage += responseStr;
                }
            }
        }

        /**////
        /// 获得指定文件的大小(如果FTP支持)
        ///
        /// 指定的文件
        /// 返回指定文件的大小
        public long GetFileSize(string filename)
        {
            Connect();
            SendCommand("SIZE " + filename);
            ReadResponse();
            if (response != 213)
            {
                errormessage += responseStr;
            }

            return Int64.Parse(responseStr.Substring(4));
        }

        /**////
        /// 上传指定的文件
        ///
        /// 要上传的文件
        public bool OpenUpload(string filename)
        {
            return OpenUpload(filename, filename, false);
        }

        /**////
        /// 上传指定的文件
        ///
        /// 本地文件名
        /// 远程要覆盖的文件名
        public bool OpenUpload(string filename, string remotefilename)
        {
            return OpenUpload(filename, remotefilename, false);
        }

        /**////
        /// 上传指定的文件
        ///
        /// 本地文件名
        /// 如果存在,则尝试恢复
        public bool OpenUpload(string filename, bool resume)
        {
            return OpenUpload(filename, filename, resume);
        }

        /**////
        /// 上传指定的文件
        ///
        /// 本地文件名
        /// 远程要覆盖的文件名
        /// 如果存在,则尝试恢复
        public bool OpenUpload(string filename, string remote_filename, bool resume)
        {
            Connect();
            SetBinaryMode(true);
            OpenDataSocket();

            bytes_total = 0;

            try
            {
                file = new FileStream(filename, FileMode.Open);
            }
            catch (Exception ex)
            {
                file = null;
                errormessage += ex.Message;
                return false;
            }

            file_size = file.Length;

            if (resume)
            {
                long size = GetFileSize(remote_filename);
                SendCommand("REST " + size);
                ReadResponse();
                if (response == 350)
                    file.Seek(size, SeekOrigin.Begin);
            }

            SendCommand("STOR " + remote_filename);
            ReadResponse();

            switch (response)
            {
                case 125:
                case 150:
                    break;
                default:
                    file.Close();
                    file = null;
                    errormessage += responseStr;
                    return false;
            }
            ConnectDataSocket();

            return true;
        }

        /**////
        /// 下载指定文件
        ///
        /// 远程文件名称
        public void OpenDownload(string filename)
        {
            OpenDownload(filename, filename, false);
        }

        /**////
        /// 下载并恢复指定文件
        ///
        /// 远程文件名称
        /// 如文件存在,则尝试恢复
        public void OpenDownload(string filename, bool resume)
        {
            OpenDownload(filename, filename, resume);
        }

        /**////
        /// 下载指定文件
        ///
        /// 远程文件名称
        /// 本地文件名
        public void OpenDownload(string remote_filename, string localfilename)
        {
            OpenDownload(remote_filename, localfilename, false);
        }

        /**////
        /// 打开并下载文件
        ///
        /// 远程文件名称
        /// 本地文件名
        /// 如果文件存在则恢复
        public void OpenDownload(string remote_filename, string local_filename, bool resume)
        {
            Connect();
            SetBinaryMode(true);

            bytes_total = 0;

            try
            {
                file_size = GetFileSize(remote_filename);
            }
            catch
            {
                file_size = 0;
            }

            if (resume && File.Exists(local_filename))
            {
                try
                {
                    file = new FileStream(local_filename, FileMode.Open);
                }
                catch (Exception ex)
                {
                    file = null;
                    throw new Exception(ex.Message);
                }

                SendCommand("REST " + file.Length);
                ReadResponse();
                if (response != 350)
                    throw new Exception(responseStr);
                file.Seek(file.Length, SeekOrigin.Begin);
                bytes_total = file.Length;
            }
            else
            {
                try
                {
                    file = new FileStream(local_filename, FileMode.Create);
                }
                catch (Exception ex)
                {
                    file = null;
                    throw new Exception(ex.Message);
                }
            }

            OpenDataSocket();
            SendCommand("RETR " + remote_filename);
            ReadResponse();

            switch (response)
            {
                case 125:
                case 150:
                    break;
                default:
                    file.Close();
                    file = null;
                    errormessage += responseStr;
                    return;
            }
            ConnectDataSocket();

            return;
        }

        /**////
        /// 上传文件(循环调用直到上传完毕)
        ///
        /// 发送的字节数
        public long DoUpload()
        {
            Byte[] bytes = new Byte[512];
            long bytes_got;

            try
            {
                bytes_got = file.Read(bytes, 0, bytes.Length);
                bytes_total += bytes_got;
                data_sock.Send(bytes, (int)bytes_got, 0);

                if (bytes_got

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-72011-1-1.html 上篇帖子: 用ftpsupport进行ftp上传 转载 下篇帖子: java操作FTP文件
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表