以下代码使用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;
}
}