C# 的FTP源代码

举报
竹叶青 发表于 2019/09/05 18:20:49 2019/09/05
【摘要】 using System.Net;using System.Net.Sockets;using System.IO;using System.Resources;using System.Text.RegularExpressions;using System.Collections;namespace crFTP{ /// <summary> /// FTP类 /// <...

using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Resources;
using System.Text.RegularExpressions;
using System.Collections;
namespace crFTP
{
   /// <summary>
   /// FTP类
   /// </summary>
   public class FTP
   {
       #region 变量声明
       /// <summary>
       /// 服务器连接地址
       /// </summary>
       public string server;
       /// <summary>
       /// 登陆帐号
       /// </summary>
       public string user;
       /// <summary>
       /// 登陆口令
       /// </summary>
       public string pass;
       /// <summary>
       /// 端口号
       /// </summary>
       public int port;
       /// <summary>
       /// 无响应时间(FTP在指定时间内无响应)
       /// </summary>
       public int timeout;
       /// <summary>
       /// 服务器错误状态信息
       /// </summary>
       public string errormessage;

       /// <summary>
       /// 服务器状态返回信息
       /// </summary>
       private string messages;
       /// <summary>
       /// 服务器的响应信息
       /// </summary>
       private string responseStr;
       /// <summary>
       /// 链接模式(主动或被动,默认为被动)
       /// </summary>
       private bool passive_mode;
       /// <summary>
       /// 上传或下载信息字节数
       /// </summary>
       private long bytes_total;
       /// <summary>
       /// 上传或下载的文件大小
       /// </summary>
       private long file_size;
       /// <summary>
       /// 主套接字
       /// </summary>
       private Socket main_sock;
       /// <summary>
       /// 要链接的网络地址终结点
       /// </summary>
       private IPEndPoint main_ipEndPoint;
       /// <summary>
       /// 侦听套接字
       /// </summary>
       private Socket listening_sock;
       /// <summary>
       /// 数据套接字
       /// </summary>
       private Socket data_sock;
       /// <summary>
       /// 要链接的网络数据地址终结点
       /// </summary>
       private IPEndPoint data_ipEndPoint;
       /// <summary>
       /// 用于上传或下载的文件流对象
       /// </summary>
       private FileStream file;
       /// <summary>
       /// 与FTP服务器交互的状态值
       /// </summary>
       private int response;
       /// <summary>
       /// 读取并保存当前命令执行后从FTP服务器端返回的数据信息
       /// </summary>
       private string bucket;
       #endregion
       #region 构造函数
       /// <summary>
       /// 构造函数
       /// </summary>
       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 = "";
       }
       /// <summary>
       /// 构造函数
       /// </summary>
       /// <param name="server">服务器IP或名称</param>
       /// <param name="user">登陆帐号</param>
       /// <param name="pass">登陆口令</param>
       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 = "";
       }
       /// <summary>
       /// 构造函数
       /// </summary>
       /// <param name="server">服务器IP或名称</param>
       /// <param name="port">端口号</param>
       /// <param name="user">登陆帐号</param>
       /// <param name="pass">登陆口令</param>
       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 = "";
       }
/// <summary>
       /// 构造函数
       /// </summary>
       /// <param name="server">服务器IP或名称</param>
       /// <param name="port">端口号</param>
       /// <param name="user">登陆帐号</param>
       /// <param name="pass">登陆口令</param>
       /// <param name="mode">链接方式</param>
       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 <= 1 ? true : false;
           main_sock = null;
           main_ipEndPoint = null;
           listening_sock = null;
           data_sock = null;
           data_ipEndPoint = null;
           file = null;
           bucket = "";
           bytes_total = 0;
           this.timeout = 10000;    //无响应时间为10秒
           messages = "";
           errormessage = "";
       }
       /// <summary>
       /// 构造函数
       /// </summary>
       /// <param name="server">服务器IP或名称</param>
       /// <param name="port">端口号</param>
       /// <param name="user">登陆帐号</param>
       /// <param name="pass">登陆口令</param>
       /// <param name="mode">链接方式</param>
       /// <param name="timeout">无响应时间(限时),单位:秒 (小于或等于0为不受时间限制)</param>
       public FTP(string server, int port, string user, string pass, int mode, int timeout_sec)
       {
           this.server = server;
           this.user = user;
           this.pass = pass;
           this.port = port;
           passive_mode = mode <= 1 ? true : false;
           main_sock = null;
           main_ipEndPoint = null;
           listening_sock = null;
           data_sock = null;
           data_ipEndPoint = null;
           file = null;
           bucket = "";
           bytes_total = 0;
           this.timeout = (timeout_sec <= 0) ? int.MaxValue : (timeout_sec * 1000);    //无响应时间
           messages = "";
           errormessage = "";
       }
       #endregion
       #region 属性
       /// <summary>
       /// 当前是否已连接
       /// </summary>
       public bool IsConnected
       {
           get
           {
               if (main_sock != null)
                   return main_sock.Connected;
               return false;
           }
       }
       /// <summary>
       /// 当message缓冲区有数据则返回
       /// </summary>
       public bool MessagesAvailable
       {
           get
           {
               if (messages.Length > 0)
                   return true;
               return false;
           }
       }
       /// <summary>
       /// 获取服务器状态返回信息, 并清空messages变量
       /// </summary>
       public string Messages
       {
           get
           {
               string tmp = messages;
               messages = "";
               return tmp;
           }
       }
       /// <summary>
       /// 最新指令发出后服务器的响应
       /// </summary>
       public string ResponseString
       {
           get
           {
               return responseStr;
           }
       }

       /// <summary>
       ///在一次传输中,发送或接收的字节数
       /// </summary>
       public long BytesTotal
       {
           get
           {
               return bytes_total;
           }
       }
       /// <summary>
       ///被下载或上传的文件大小,当文件大小无效时为0
       /// </summary>
       public long FileSize
       {
           get
           {
               return file_size;
           }
       }
       /// <summary>
       /// 链接模式:
       /// true 被动模式 [默认]
       /// false: 主动模式
       /// </summary>
       public bool PassiveMode
       {
           get
           {
               return passive_mode;
           }
           set
           {
               passive_mode = value;
           }
       }
       #endregion
       #region 操作
       /// <summary>
       /// 操作失败
       /// </summary>
       private void Fail()
       {
           Disconnect();
           errormessage += responseStr;
           //throw new Exception(responseStr);
       }
       /// <summary>
       /// 下载文件类型
       /// </summary>
       /// <param name="mode">true:二进制文件 false:字符文件</param>
       private void SetBinaryMode(bool mode)
       {
           if (mode)
               SendCommand("TYPE I");
           else
               SendCommand("TYPE A");
           ReadResponse();
           if (response != 200)
               Fail();
       }
       /// <summary>
       /// 发送命令
       /// </summary>
       /// <param name="command"></param>
       private void SendCommand(string command)
       {
           Byte[] cmd = Encoding.ASCII.GetBytes((command + "\r\n").ToCharArray());
           if (command.Length > 3 && command.Substring(0, 4) == "PASS")
           {
               messages = "\rPASS xxx";
           }
           else
           {
               messages = "\r" + command;
           }
           try
           {
               main_sock.Send(cmd, cmd.Length, 0);
           }
           catch (Exception ex)
           {
               try
               {
                   Disconnect();
                   errormessage += ex.Message;
                   return;
               }
               catch
               {
                   main_sock.Close();
                   file.Close();
                   main_sock = null;
                   main_ipEndPoint = null;
                   file = null;
               }
           }
       }
private void FillBucket()
       {
           Byte[] bytes = new Byte[512];
           long bytesgot;
           int msecs_passed = 0;
           while (main_sock.Available < 1)
           {
               System.Threading.Thread.Sleep(50);
               msecs_passed += 50;
               //当等待时间到,则断开链接
               if (msecs_passed > 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;
       }

       /// <summary>
       /// 返回服务器端返回信息
       /// </summary>
       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";
           }
       }

       /// <summary>
       /// 打开数据套接字
       /// </summary>
       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]) << 8) + int.Parse(pasv[5]);
               try
               {
                   CloseDataSocket();
                   data_sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                   //#if NET1
                   data_ipEndPoint = new IPEndPoint(Dns.GetHostByName(server).AddressList[0], port);
                   //#else
                   //                    data_ipEndPoint = new IPEndPoint(System.Net.Dns.GetHostEntry(server).AddressList[0], port);
                   //#endif
                   data_sock.Connect(data_ipEndPoint);
               }
               catch (Exception ex)
               {
                   errormessage += "Failed to connect for data transfer: " + ex.Message;
                   return;
               }
           }
           else
           {
               Connect();
               try
               {
                   CloseDataSocket();
                   listening_sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                   // 对于端口,则发送IP地址.下面则提取相应信息
                   string sLocAddr = main_sock.LocalEndPoint.ToString();
                   int ix = sLocAddr.IndexOf(':');
                   if (ix < 0)
                   {
                       errormessage += "Failed to parse the local address: " + sLocAddr;
                       return;
                   }
                   string sIPAddr = sLocAddr.Substring(0, ix);
                   // 系统自动绑定一个端口号(设置 port = 0)
                   System.Net.IPEndPoint localEP = new IPEndPoint(IPAddress.Parse(sIPAddr), 0);
                   listening_sock.Bind(localEP);
                   sLocAddr = listening_sock.LocalEndPoint.ToString();
                   ix = sLocAddr.IndexOf(':');
                   if (ix < 0)
                   {
                       errormessage += "Failed to parse the local address: " + sLocAddr;
                   }
                   int nPort = int.Parse(sLocAddr.Substring(ix + 1));
                   // 开始侦听链接请求
                   listening_sock.Listen(1);
                   string sPortCmd = string.Format("PORT {0},{1},{2}",
                                                   sIPAddr.Replace('.', ','),
                                                   nPort / 256, nPort % 256);
                   SendCommand(sPortCmd);
                   ReadResponse();
                   if (response != 200)
                       Fail();
               }
               catch (Exception ex)
               {
                   errormessage += "Failed to connect for data transfer: " + ex.Message;
                   return;
               }
           }
       }

       private void ConnectDataSocket()
       {
           if (data_sock != null)        // 已链接
               return;
           try
           {
               data_sock = listening_sock.Accept();    // Accept is blocking
               listening_sock.Close();
               listening_sock = null;
               if (data_sock == null)
               {
                   throw new Exception("Winsock error: " +
                       Convert.ToString(System.Runtime.InteropServices.Marshal.GetLastWin32Error()));
               }
           }
           catch (Exception ex)
           {
               errormessage += "Failed to connect for data transfer: " + ex.Message;
           }
       }


本文转载自异步社区

原文链接:

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。