使用嵌套字用FTP协议进行文件上传下载!

 以下代码使用C#完成!完成。

  
using System;
using System.Net.Sockets;


/// <summary>
/// Ftp 的摘要说明。
/// </summary>
public class Ftp
{
  public Ftp()
  {
   //
   // TODO: 在此处添加构造函数逻辑
   //
  }
  string _ser;
  public string Server
  {
   set{ _ser=value;}
   get{return _ser;}
  }
  string _port;
  public string Port
  {
   set{_port=value;}
   get{return _port;}
  }
  string _user;
  public string User
  {
   set{ _user=value;}
   get{return _user;}
  }
  string _pws;
  public string Password
  {
   set{ _pws=value;}
   get{return _pws;}
  }
  bool  _IsLog;
  public bool IsLogined
  {
   set{ _IsLog=value;}
   get{return _IsLog;}
  }
  int  _MsgID;
  public int MsgID
  {
   set{ _MsgID=value;}
   get{return _MsgID;}
  }
  System.Windows.Forms.Label _infx=new System.Windows.Forms.Label() ;
  public System.Windows.Forms.Label InfsShow
  {
   set{_infx=value;}
   get{return _infx;}
  }
  System.Windows.Forms.ListBox  _infs=new System.Windows.Forms.ListBox();
  public System.Windows.Forms.ListBox  InfsList
  {
   set{_infs=value;}
   get{return _infs;}
  }
  System.Windows.Forms.ProgressBar   _pb=new  System.Windows.Forms.ProgressBar() ;
  public System.Windows.Forms.ProgressBar  Progress
  {
   set{_pb=value;}
   get{return _pb;}
  }
  public string NowInf;
  System.Net.Sockets.TcpClient tcFtp;
  NetworkStream Stm;
  public bool Login()
  {
   try
   {
    SetInf("正在连接服务器...");
    tcFtp=new TcpClient(_ser, System.Convert.ToInt32(_port));//连接服务器
    Stm= tcFtp.GetStream();//获取网络流
    byte[] data=new byte[255];
    int bytes;
    SetInf("等待服务器就绪!");
    bytes=Stm.Read(data,0,data.Length);
    string msg=System.Text.Encoding.ASCII.GetString(data,0,bytes);//读取登录成功的消息
    if (msg.Substring(0,3)=="220")
    {
     SetInf(msg);
     if (DoCmd("USER " + _user+" ","331"))
     {
      if (DoCmd("PASS " + _pws,"230"))
      {
      
       SetInf("服务器就绪!");
       this.IsLogined=true;
       return true;
      }  
      SetInf("密码错误!",230);
      return false;
     }
     SetInf("用户名错误",331);
     return false;
    }
    else
    {
     SetInf("服务器没有正确响应!",220);
     return false;
    }

    
   }
   catch (System.Exception ex)
   {
    NowInf=ex.Message ;
    _infx.Text=NowInf;
    return false;
   }

    

  }

  /// <summary>
  ///
  /// </summary>
  /// <param name="cmd"></param>
  /// <param name="wait">匹配前面的字符就可以了</param>
  /// <returns></returns>
  private bool DoCmd(string cmd,string wait)
  {
   string msg=DoCommand(cmd);
    SetInf(msg);
   if (msg.IndexOf("/r/n")>=0)
   {
    string xx=msg.Substring(msg.IndexOf("/r/n")) ;

    msg=(xx=="/r/n"?msg:xx);
    msg=msg.Replace("/r/n","");
   }
   msg+="/r/n";
   return (msg.Substring(0,wait.Length).ToLower()==wait.ToLower() );//如果msg的前部分是wait,则返回成功.
  }
  private bool RetOk(string s1,string s2)
  {
   string msg=s1;
   if (msg.IndexOf("/r/n")>=0)
   {
    string xx=msg.Substring(msg.IndexOf("/r/n")) ;
    msg=(xx=="/r/n"?msg:xx);
       msg=msg.Replace("/r/n","");
   }
   s1=msg+"/r/n";
   return (s1.Substring(0,s2.Length).ToLower()==s2.ToLower() );//如果msg的前部分是wait,则返回成功.
  }
  private string DoCommand(string cmd)
  {
   string msg=cmd;//+System.Text.Encoding.ASCII.GetString(vbnull);
   byte[] data=System.Text.Encoding.ASCII.GetBytes(msg+"/r/n");
   Stm.Write(data,0,data.Length);
            System.Windows.Forms.Application.DoEvents();
   System.Windows.Forms.Application.DoEvents();
   System.Windows.Forms.Application.DoEvents();
   System.Windows.Forms.Application.DoEvents();
   System.Windows.Forms.Application.DoEvents();

   data=new byte[255];
   int bytes;
   while(Stm.DataAvailable==false)  
   {
    System.Windows.Forms.Application.DoEvents() ;
    NowInf="正在等待服务器响应!";
   }
   bytes=Stm.Read(data,0,data.Length);
   msg=System.Text.Encoding.ASCII.GetString(data,0,bytes);
   return msg;
  }

  private void SetInf(string msg)
  {
   if( msg.IndexOf("/r/n")>=0)
   {
    msg=msg.Substring(0,msg.LastIndexOf("/r/n")-"/r/n".Length );
    msg+=" "+ System.DateTime.Now.TimeOfDay.ToString();
   }
   NowInf=msg;
   _infx.Text=NowInf;
   _infs.Items.AddRange(msg.Split("/r/n".ToCharArray()));
   System.Windows.Forms.Application.DoEvents();
   _infs.SelectedIndex=_infs.Items.Count-1;
   System.Windows.Forms.Application.DoEvents();
   System.Windows.Forms.Application.DoEvents();
  }

  private void SetInf(string msg,int msgid)
  {
   SetInf(msg);
   _MsgID=msgid;
  }

  private string GetMsg()
  {
   string msg;
   byte[] data=new byte[1024];
   int bytes;
   System.Windows.Forms.Application.DoEvents();
   System.Windows.Forms.Application.DoEvents();
   System.Windows.Forms.Application.DoEvents();
   System.Windows.Forms.Application.DoEvents();
   while(Stm.DataAvailable==false)//如果没有信息可读,等待服务器响应.  
   {
    
    System.Windows.Forms.Application.DoEvents() ;
   }
   bytes=Stm.Read(data,0,data.Length);//读取数据
   msg=System.Text.Encoding.ASCII.GetString(data,0,bytes);//转换为字符
   int rn= msg.IndexOf("/r/n",0);//查找换行符号
   if (rn>0)
   {
    string mg=msg.Substring(rn);//这里是为了防止传输来多行数据,我试图加大缓冲,也是这样.
    if( mg.Length>2)//在这里处理如同226这样消息.
    {                 //前面一次返回接受了一部分,第二次接受到了前面的一部分,在这里用来分开他们
     mg=mg.Substring(2);
     msg=mg;
    }
   }
   SetInf(msg);
   return msg;
  }
  /// <summary>
  /// 注销登录
  /// </summary>
  /// <returns>成功时返回真</returns>
  public bool Logout()
  {
   this.IsLogined=false;
   bool ok=DoCmd("QUIT","221");
   SetInf("已断开服务器!",221);
   return ok;
  
  }
  public bool SetCurDir(string Path)
  {

    
   if (DoCmd("CWD "+Path,"250")==false)//"" is current directory.
   {
    SetInf("确认当前目录失败!",257);
    return false;
   }
   if (DoCmd("PWD "+Path,"257")==false)//"" is current directory.
   {
    SetInf("确认当前目录失败!",257);
    return false;
   }
   return true;
  }
  public string  GetCurDir()
  {

    
   string msg=DoCommand("PWD");
   string[] st=msg.Split((char)34);
   return st[1];
  }

  public bool Delete(string FileName)
  {
   return DoCmd("DELE "+FileName,"250");
  }

  /// <summary>
  /// 上传文件
  /// </summary>
  /// <param name="FileName">要上传的本地文件</param>
  /// <param name="SvrPath">服务器目标路径.</param>
  /// <returns>传输成功返回真.</returns>
  public bool UploadFile(string FileName)
  {
   _pb.Value=5;
   if (this.IsLogined==false)
   {
    SetInf("没有连接到服务器或没有登录!");
    return false;
   }
   if (DoCmd("TYPE I","200")==false)//Type set to I.
   {
    SetInf("执行Type i失败!",200);
    return false;  
   }
   _pb.Value=10;
   string[] pt=FileName.Split("//".ToCharArray());
   string filename=pt[pt.Length-1] ;//SvrPath+"/"+pt[pt.Length-1] ;
   string tmp1=DoCommand("SIZE "+ filename);
   SetInf(tmp1);
   if (RetOk(tmp1,"550")!=true)//50 /bbs/Dv_ForumNews/广告.txt: No such file.
   {
    if (RetOk(tmp1,"501")!=true)
    {
     SetInf("文件已存在!",550);
     return false;  
    }
    else
    {
     SetInf("文件名为空,请指定文件名!",501);
     return false;  
    }

   }
   _pb.Value=15;
   if (DoCmd("MODE S" ,"200")==false)//Type set to I.
   {
    SetInf("模式设置失败!");
    //return false;  
   }
   /////获取传输文件的ip和段口
   string tmp2 =DoCommand("PASV");
   SetInf(tmp2);
   if (RetOk(tmp2,"227")==false)//Type set to I.
   {
    SetInf("服务器没有返回227,无法知道端口,也无法开始传输文件!",227);
    return false;  
   }
   string[] ips=GetIP( tmp2);
   ///////////////////
   TcpClient tcm;
   try
   {
    _pb.Value=20;
    SetInf("正在连接文件传输服务器!");
    tcm=new TcpClient(ips[0],System.Convert.ToInt32(ips[1]));//连接传输服务器.
   }
   catch (System.Exception ex1)
   {
    SetInf("连接文件传输服务器时出错:IP地址:"+ips[0]+"端口:" + ips[1]+"  相关信息:" + ex1.Message );
    return false;
   }
   if (DoCmd("STOR "+ filename,"150")==false)//发送传输文件的指令.返回应该是150,否则出错
   {
    SetInf("开始传输文件的指令服务器响应的不是150,不知道服务器是不是准备接受文件!",150);
    return false;  
   }
   //读取文件///////////////////////
   SetInf("正在读取文件,准备传输...");
   System.IO.FileStream fs;
   byte[] fbins;
   try
   {
    _pb.Value=25;
    fs=new System.IO.FileStream(FileName,System.IO.FileMode.Open,System.IO.FileAccess.Read);
    fbins=new byte[fs.Length] ;
    fs.Read(fbins,0,System.Convert.ToInt32(fs.Length));
   }
   catch( System.Exception ex2)
   {
    SetInf("文件读取失败,失败原因:"+ex2.Message);
    return false;
   }
   _pb.Value=35;
   /////////////////////////////////////////////////////
   NetworkStream tmx=tcm.GetStream();//获得流
   SetInf("正在向网络数据流中写入数据...");
   _pb.Value=45;
   tmx.Write(fbins,0,fbins.Length);//写入信息
   tmx=null;
   tcm.Close();
   _pb.Value=55;
   if (RetOk(GetMsg(),"226")==false)//一般226信息为两次 ,本次是说明磁盘目前可用大小已经使用大小
   {

   }
  
   string tmp3;
   _pb.Value=65;
   tmp3=DoCommand("SIZE "+ filename);//获取大小.
   SetInf(tmp3);
   _pb.Value=75;
   if (RetOk(tmp3,"213"))//返回大小
   {
    SetInf("正在核对文件大小");
    int ln=System.Convert.ToInt32(tmp3.Substring(4));//得到远程文件的大小
    _pb.Value=89;
    if( ln==fbins.Length)//如果大小相同.说明完整传输.
    {
     SetInf("文件传输成功!",0);
     return true;
    }
    SetInf("文件传输后文件大小不一致!",213);
    return false;
   }
   _pb.Value=100;
   SetInf("文件传输成功,但确认文件大小时服务器响应的不是213!因此无法保证数据传输是否正确!",213);
  
   return false;
  }

  /// <summary>
  /// 从消息里提取用于传输文件的服务器地址和端口
  /// </summary>
  /// <param name="Inf">消息</param>
  /// <returns>数组,0为ip地址,1为端口.</returns>
  private string[] GetIP(string Inf)
  {
   string[] rt=new string[2];
   if (Inf.IndexOf("(")>0 )
   {
    string ips=Inf.Substring( Inf.IndexOf("(")+1);
    ips=ips.Substring(0,ips.IndexOf(")"));
    string[] ip=ips.Split(",".ToCharArray());
    rt[0]=ip[0]+"."+ip[1]+"."+ip[2]+"."+ip[3];//前面4组byte是ip地址.
    int x1=System.Convert.ToInt16(ip[4]);//ip地址
    int x2=System.Convert.ToInt16(ip[5]);//端口
    int rtx=x1*256+x2;//计算端口.消息里后两组byte是端口,前者乘256加上后者就是服务器给你的端口.
    rt[1]=rtx.ToString();
   }
   return rt;
  
  }
  public bool DownloadFile(string SvrFileName,string SaveToFileName)
  {
   string FileName=SvrFileName;
   if (this.IsLogined==false)
   {
    SetInf("没有连接到服务器或没有登录!");
    return false;
   }
   _pb.Value=5;
   DoCmd("NOOP","200");
  
   if (DoCmd("TYPE I","200")==false)//Type set to I.
   {
    SetInf("执行Type i失败!",200);
    return false;  
   }
   _pb.Value=10;
   DoCmd("NOOP","200");

   _pb.Value=25;
   if (DoCmd("MODE S" ,"200")==false)//Type set to I.
   {
    SetInf("模式设置失败!",200);
    //return false;  
   }
   /////获取传输文件的ip和段口
   DoCmd("NOOP","200");
   _pb.Value=34;
   string tmp2 =DoCommand("PASV");
   SetInf(tmp2);
    _pb.Value=40;;
   if (RetOk(tmp2,"227")==false)//Type set to I.
   {
    SetInf("服务器没有返回227,无法知道端口,也无法开始传输文件!",227);
    return false;  
   }
   string[] ips=GetIP( tmp2);
   TcpClient tcm;
   try
   {
    _pb.Value=50;
    SetInf("正在连接文件传输服务器!");
    tcm=new TcpClient(ips[0],System.Convert.ToInt32(ips[1]));//连接传输服务器.
   }
   catch (System.Exception ex1)
   {
    SetInf("连接文件传输服务器时出错:IP地址:"+ips[0]+"端口:" + ips[1]+"  相关信息:" + ex1.Message );
    return false;
   }
   _pb.Value=55;
   DoCmd("NOOP","200");
   string inf=DoCommand("RETR "+ FileName);
   if (inf.IndexOf("150")==-1)
   {
    SetInf(inf);
    return false;
   }

    _pb.Value=60;
   SetInf("正在准备接收文件...");
   System.IO.FileStream fs;
    
   try
   {
    fs=new System.IO.FileStream(SaveToFileName,System.IO.FileMode.OpenOrCreate ,System.IO.FileAccess.ReadWrite );
   }
   catch( System.Exception ex2)
   {
    SetInf("文件创建或打开失败,失败原因:"+ex2.Message);
    return false;
   }
   /////////////////////////////////////////////////////
   ///
   NetworkStream tmx=tcm.GetStream();//获得流
   _pb.Value=70;
   SetInf("正在接收文件...");
   int i=0;
   int c=0;
   do
   {
  
    byte[] dats=new byte[10240];
    i=tmx.Read(dats,0,dats.Length);
    c+=i;
    System.Windows.Forms.Application.DoEvents();
    System.Windows.Forms.Application.DoEvents();
    System.Windows.Forms.Application.DoEvents();
    fs.Write(dats,0,i);
    System.Windows.Forms.Application.DoEvents();
    System.Windows.Forms.Application.DoEvents();
    System.Windows.Forms.Application.DoEvents();
    this.InfsShow.Text=c+"字节已复制.";
   }
   while (i>0 );
   c=0;
   this.InfsShow.Text="正在保存文件!";
   fs.Close();
   tmx=null;
   tcm.Close();
   DoCmd("NOOP","200");
   this.InfsShow.Text="";
   return true;
  }
}

上一篇:多线程委托回调


下一篇:HHP格式解析!