FTP协议将使用两条单独的TCP连接,一条专用于发送FTP命令,另一条则专用于传递数据。初始建立连接时,服务器在21号端口上接收来自客户端的命令连接。当需要传送数据时(文件列表、文件数据等),客户端向服务器发出Port命令,并进入监听状态,等待来自服务器的数据连接请求。
首先我们利用VC++6.0的AppWizard创建一个基于对话框的应用程序,命名为FtpClientDemo。调整主对话框的形式如图1,为程序生成五个基于CAsyncSocket的新类,限于篇幅,只列出主要代码。
■CCommandSocket类的主要代码
voidCCommandSocket::OnReceive(intnErrorCode)
{
//这个函数使得服务器的应答消息显示在编辑框上
charbuffer=newchar[4096];
memset(buffer,0,4096);
this-〉Receive(buffer,1024,0);
//接收应答消息
MessageList+=buffer;
m_ReturnMessage-〉SetWindowText(MessageList);
deletebuffer;
}
■CFileSocket类的主要代码
voidCFileSocket::OnReceive(intnErrorCode)
{
//函数将收到的文件数据写到文件中
if(File==NULL)
{File=newCFile();
File-〉Open(FileName,CFile::modeWrite|CFile::modeCreate);
}
charbuffer=newchar[4096];
memset(buffer,0,4096);
this-〉Receive(buffer,4096,0);
ReceiveString=buffer;
File-〉Write(ReceiveString,ReceiveString.GetLength());
deletebuffer;
}
■CReceiveSocket类的主要代码
voidCReceiveSocket::OnReceive(intnErrorCode)
{
//接收服务器传来的文件列表消息
CStringReceiveString,Temp;
charbuffer=newchar[4096];
memset(buffer,0,4096);
this-〉Receive(buffer,4096,0);//接收消息
ReceiveString+=buffer;
deletebuffer;
//将文件列表从收到的消息字符串中分离出来,并显示在列表框中
while(!ReceiveString.IsEmpty())
{intp=ReceiveString.Find("\r\n");
if(p!=-1)
{Temp=ReceiveString.Left(p);
ReceiveString=ReceiveString.Right(ReceiveString.GetLength()-p-2);
DisplayMessage-〉AddString(Temp);
}
}
}
■CPortSocket类主要代码
voidCPortSocket::OnAccept(intnErrorCode)
{
//根据不同的标志选择相应的数据连接类,以接受服务器端的数据连接请求
if(Flag==LISTFILE)
//若程序要求对目录进行列表,则采用CReceiveSocket类
{DataSocket=newCReceiveSocket(FileList);
this-〉Accept(DataSocket);
}
elseif(Flag==DOWNLOAD)
//若程序要求下载文件,则生成CFileSocket类的对象
{FileSocket=newCFileSocket(FileName);
this-〉Accept(FileSocket);
}
}
■主对话框类CFtpClient-DemoDlg的主要代码
voidCFtpClientDemoDlg::OnFileList()
//响应“文件列表”按钮、列表目录
{CStringTemp;
if(ControlSocket==NULL)
{
//连接到FTP服务器
ControlSocket=newCCommandSocket(&&m_ReturnMessage);
ControlSocket-〉Create();
m_Server.GetWindowText(Temp);
ControlSocket-〉Connect(Temp,21);
//FTP服务器在21号端口接收连接
}
m_User.GetWindowText(Temp);
Temp="USER"+Temp+"\r\n";
ControlSocket-〉Send(Temp,Temp.GetLength(),0);
//发User命令,验证用户
m_Pass.GetWindowText(Temp);//m_Pass为“口令”编辑框的对应控制
Temp="PASS"+Temp+"\r\n";
ControlSocket-〉Send(Temp,Temp.GetLength(),0);
//发Pass命令,校验口令
LisentPort(LISTFILE);
//数据连接的对象为目录列表
ControlSocket-〉Send("LIST\r\n",7,0);
//发List命令,要求列表目录
}
voidCFtpClientDemoDlg::OnDownLoad()
//下载文件
{
CStringString;
LisentPort(DOWNLOAD);
//获得要下戴文件的文件名
m_LocalFile.GetWindowText(String);
//m_LocalFile为“文件名”编辑框的对应控制
String="RETR"+String+"\r\n";
ControlSocket-〉Send(String,String.GetLength(),0);
//发RETR命令,下载文件
}
voidCFtpClientDemoDlg::LisentPort(UINTFlag)
{
//根据要求选择不同的数据连接对象
if(LisentSocket!=NULL)
//清空LisentSocket
{LisentSocket-〉Close();
deleteLisentSocket;
LisentSocket=NULL;
}
if(Flag==LISTFILE)
//如果为目录列表数据连接对象
{LisentSocket=newCPortSocket(LISTFILE);
LisentSocket-〉SetListBox(&&m_FileList);
//传列表框到CLisentSocket类中
}
elseif(Flag==DOWNLOAD)
//如果为文件传输数据连接对象
{CStringString;
m_LocalFile.GetWindowText(String);
LisentSocket=newCPortSocket(DOWNLOAD);
LisentSocket-〉SetFileName(String);
//传文件名到CLisentSocket类中
}
LisentSocket-〉Create();
//建立Socket并进行监听,等待FTP服务器进行数据连接
LisentSocket-〉Listen();
//取得数据连接Socket的IP地址和监听端口,并把它们作为Port命令的参数
SOCKADDR_INlisting_address,control_address;
intaddr_size;
addr_size=sizeof(listing_address);
LisentSocket-〉GetSockName((SOCKADDR)&&listing_address,&&addr_size);//取IP地址
ControlSocket-〉GetSockName((SOCKADDR)&&control_address,&&addr_size);//取端口
unsignedcharport=(unsignedchar)&&(listing_address.sin_port);
unsignedcharhost=(unsignedchar)&&(control_address.sin_addr);
CStringstrBuffer;
strBuffer.Format("PORT%i,%i,%i,%i,%i,%i\r\n",(int)host[0],(int)host[1],(int)host[2],(int)host[3],(int)port[0],(int)port[1]);
ControlSocket-〉Send(strBuffer,strBuffer.GetLength(),0);
//发送Port命令,进行数据连接
}
以上代码在VC++6.0、Windows98上运行通过
用FTP协议编制FTP客户端程序
0
相关文章