MFC FTP文件传输要点.docx
《MFC FTP文件传输要点.docx》由会员分享,可在线阅读,更多相关《MFC FTP文件传输要点.docx(42页珍藏版)》请在冰豆网上搜索。
MFCFTP文件传输要点
大学研究生堂下考试答卷
2014-2015学年第1学期
考试科目
姓名
年级
专业
2014年12月28日
《面向对象程序设计》课程报告
学号:
姓名:
学院:
题目
基于MFC的聊天室与FTP文件传输系统
选
题
背
景
首先经过一个学期关于C++的学习,我们希望能够运用所学的知识做出一些具有使用价值的产品。
另外,由于本身专业是通信工程,基于对通信软件编程方面兴趣,希望能够在完成课程设计的同时能够加深自己对通信底层原理的理解。
因此我们选择的题目是基于MFC的网络聊天室与FTP文件传输的编程。
并且希望最后编写好的程序能够在同学之间进行交流以及文件共享方面具有一定的实用价值。
最后,希望在完成编程的过程中提高自己C++方面的能力以适应今后的学习与发展。
实现的功能:
1.支持多个客户端与服务器端之间的连接。
2.支持客户端与客户端之间的通信。
3.支持服务器端与客户端之间的通信。
4.FTP客户端方面支持文件的下载、上传、以及删除的功能。
5.FTP文件传输方面拥有两个客户端,一个是用于单线程的,另一个是用于多线程的,本实例对两个客户端的工作方式进行了对比。
实现环境及开发工具:
1.windows7/8.1操作系统(实现环境)
2.visualstudio2010/2013(开发工具)
3.MSDN2008(帮组文档)
4.StarUML(UML制图工具)
基
础
知
识
由于本实例是通信网络编程,使用到了很多网络通信方面的知识,其中包括WinSock编程以及WinInet编程。
下面介绍一下两类编程的基础知识。
一、WinSock编程
1.介绍
套接字是支持TCP/IP网络通信的基本操作单元。
多个TCP连接或多个应用程序进程可能需要通过同一个TCP协议端口传输数据。
为了区别不同的应用程序进程和连接,许多计算机操作系统为应用程序与TCP/IP协议交互提供了称为套接字(Socket)的接口。
套接字为不同的应用进程使用网络协议进行数据交换提供了接口,主要用于应用层与传输层之间。
套接字分为三类:
流式套接字、报文套接字以及原始套接字。
其中最常使用的是流式套接字与报文套接字。
流式套接字是面向连接的,在数据传输之前需要在双方之间建立起连接,主要用于TCP业务;报文套接字是面向无连接的,在数据传输之间无需建立连接,只需要知道对方的IP网络地址已经对应的业务端口就可以把业务发送到目的端,报文套接字主要是用于传输基于UDP的业务。
由于Windows提供了SOCKET的API函数,因此简化了整个套接字应用编程的难度,但是对于一般的初学者来说使用SOCKETAPI函数进行编程还是具有一定的难度,其主要适用于对整个协议工作过程有深入了解的专业人士使用。
因此为了降低编程的门槛,微软公司将SOCKETAPI函数封装为了一个新的类CAsyncSocket类,通过调用CasyncSocket类的成员函数就能够完成网络编程的功能。
但是,CasyncSocket的封装性对于一般用户来说还是太过于复杂,对于一般人的使用还是有一定的难度,因此微软又在CAsyncSocket类的基础上派生了CSocekt类,极大地简化了套接字的编程。
本实例采用的就是CSocket编程。
2.套接字工作过程
由于本实例是采用C/S模式进行编程,是由客户端与服务器端组成的。
流式套接字与报文套接字编程的原理是不一样的。
流式套接字原理
流式套接字是面向连接的,在进行数据传输之前需要在服务器与客户端之间先建立起连接。
其建立连接的过程主要分为四步。
.服务器端初始化套接字并绑定端口。
.服务器端套接字启动监听状态,调用Listen()函数。
.客户端端建立套接字并绑定端口。
.客户端请求连接。
.服务器端接受连接请求。
其工作过程见图1.1。
图1.1:
流式套接字工作过程
报文套接字工作原理
报文套接字不需要在数据传输之间建立连接,只需绑定对应的端口然后将数据发往对应的网络地址即可。
其工作过程见图1.2。
图1.2:
报文套接字工作过程
二、WinInet编程
WinInet是windowsinternet扩展应用程序高级编程接口,是专为开发具有Internet功能的客户机端应用程序而提供的。
它有两种形式:
WinInetAPI包含一个C语言的函数集,MFCWinInet类则是对前者的面向对象的封装。
WinInet主要用于Internet关于FTP文件传输协议,HTTP超文本传输协议以及Gopher文件传输协议。
MFC中WinInet包含的类
.CinternetSession类:
由CObject类派生,代表应用程序的一次Internet会话,每个访问Internet的应用程序都需要一个CInternetSession类对象。
.连接类:
连接类主要包括CinternetConnection类以及它的派生类CFtpConnection类、CHttpConnection类和CGopherConnection类。
.文件类:
包括CInternetFile类以及它派生的CHttpFile类和CGopherFile类,另外文件查找类CFileFind也是文件类。
.CInternetException类:
MFCWinInet类的成员函数在执行时所发生的错误或异常,往往用try/catch逻辑结构来处理异常。
WinInet编程的步骤
.创建CInternetSession类对象,创建并初始化Internet会话
.创建连接对象类,建立CInternetSession对象与网络服务器的连接,也就是应用程序与服务器的连接。
本实例创建CFtpConnection类。
.创建文件检索类,对文件进行检索。
.创建异常类CInetnetException类,处理错误。
.关闭各种类,释放资源。
三、多线程编程
Windows本身是一个多进程多线程的操作系统,因此在日常的应用编写中最好能够使用多线程的技术。
在windows环境下开发多线程应用程序可以利用提供的Win32API接口函数,也可以利用微软提供的MFC类库进行开发。
两种方式对于多线程编程原理是一样的,用户可以根据需要选择相应的工具。
本实例主要用到的是MFC类库实现多线程调度与处理。
MFC类库提供了对多线程编程的支持,使得多线程能方便的实现。
MFC区分两种类型的线程:
工作线程和用户接口线程。
工作线程没有消息机制,通常用来执行后台计算和维护任务。
MFC为用户接口线程提供消息机制,用来处理用户的输入,响应用户产生的事件消息。
但对于Win32的API来说,这两种线程并没有区别,它只需要线程的启动地址便启动线程执行任务。
用户接口线程的一个典型应用就是类CWinApp,类CWinApp是CWinThread类的派生类,应用程序的主线程是由它提供,并由它负责处理用户产生的事件和消息。
系
统
设
计
本实例借用StarUML软件绘制了整个程序的UML类视图,这个类视图在前期的代码编写上提供了很多帮助。
UML类视图能够清晰地表明类与类之间的关系以及各个类所具有成员函数与成员变量。
1.客户端类视图
2.服务器端类视图
系
统
实
现
FTP文件传输客户端
一、单线程FTP客户端设计步骤
1.之前在CClientDlg类中已经添加了两个对话框的资源,为IDD_DIALOG_FTP对话框添加控件以及为控件添加成员变量。
其界面布局以及成员变量之间的关系分别如图2.1表2.1所示。
在头文件中添加头文件#include。
图2.1:
FTP客户端
表2.1:
单线程客户端添加成员变量
控件类型
ID
变量名
控件类型
ID
变量名
CButton
IDC_BUTTON_DO
WNLOAD
m_btnDownload
CButton
IDC_BUTTON_R
MOVE
m_btnrem
ove
CButton
IDC_BUTTON_U
PLOAD
m_btnUp
load
CString
IDC_EDIT_PWD
m_strPwd
CString
IDC_EDIT_USER
NAME
m_strUser
name
CString
IDC_EDIT_SERVE
RNAME
m_strServername
CListBox
IDC_LIST_FIEL
m_listFile
CButton
IDOK
m_btnquery
2.为按钮添加消息响应:
为“查询”按钮添加消息响应voidCFtpDlg:
:
OnQuery(),用于查询FTP服务器端上的文件。
具体代码如下:
voidCFtpDlg:
:
OnQuery()
{
//TODO:
在此添加控件通知处理程序代码
//m_btnDownload.EnableWindow(TRUE);
strflag="";//初始化初始路径
UpdateData(TRUE);
while(m_listFile.GetCount()!
=0)m_listFile.DeleteString(0);//清空列表框
List("");//查询服务器上的文件
m_btnUpload.EnableWindow(TRUE);
m_btnDownload.EnableWindow(FALSE);
m_btnremove.EnableWindow(FALSE);
}
为“下载”按钮添加消息响应voidCFtpDlg:
:
OnDownload(),用于下载FTP服务器端的文件。
具体代码如下:
voidCFtpDlg:
:
OnDownload()
{
//TODO:
在此添加控件通知处理程序代码
intsel=m_listFile.GetCurSel();
CStringstrfilename;
m_listFile.GetText(sel,strfilename);//获取要下载文件的文件名
if(strfilename.GetAt(0)!
='[')//判断是否为文件夹,如果不为文件夹便下载
{
CStringstrpathname;
CFileDialogdlg(FALSE,"",strfilename);//新建一个文件对话框,FALSE表示为存储类型对话框,详情见MSDN
if(dlg.DoModal()==IDOK)
{
strpathname=dlg.GetPathName();//保存文件要存储的路径
strfilename=strflag+strfilename;
if(Download(strfilename,strpathname))//调用download函数下载文件
MessageBox("下载成功");
else
MessageBox("下载失败");
}
}
else
MessageBox("不能下载目录");
}
为“上传”按钮添加消息响应voidCFtpDlg:
:
OnUpload(),用于上传文件到FTP服务器。
具体代码如下:
voidCFtpDlg:
:
OnUpload()
{
//TODO:
在此添加控件通知处理程序代码
UpdateData(TRUE);
CStringstrfilename;
CStringstrpathname;
CFileDialogdlg(TRUE);//创建用于上传类型的文件对话框
if(dlg.DoModal()==IDOK)
{
strfilename=dlg.GetFileName();//保存文件名
strpathname=dlg.GetPathName();//保存文件路径
if(Upload(strpathname,strfilename))//调用上传函数
MessageBox("上传成功");
else
MessageBox("上传失败");
}
else
MessageBox("请选择文件");
}
为“删除”按钮添加消息响应voidCFtpDlg:
:
OnRemove(),用于删除FTP服务器上的文件。
具体代码如下:
voidCFtpDlg:
:
OnRemove()//删除文件
{
//TODO:
在此添加控件通知处理程序代码
UpdateData(TRUE);
CInternetSession*psession;
CFtpConnection*pconnect;
pconnect=NULL;
psession=newCInternetSession(AfxGetAppName(),1,PRE_CONFIG_INTERNET_ACCESS);
try{
pconnect=psession->GetFtpConnection(m_strServername,m_strUsername,m_strPwd);
}
catch(CInternetException*e)
{
e->Delete();
pconnect->Close();
}
intsel=m_listFile.GetCurSel();
CStringstrfilename;
m_listFile.GetText(sel,strfilename);
if(strfilename.GetAt(0)!
='[')
{
intflag=MessageBox("是否删除文件","删除",MB_YESNO);
if(flag==IDYES)
{
pconnect->Remove(strfilename);
MessageBox("删除成功");
}
}
else
MessageBox("不能删除文件夹");
}
3.为CFtpDlg类添加成员函数
添加用于查询服务器文件的函数voidCFtpDlg:
:
List(CStringstrsourcename),具体代码:
voidCFtpDlg:
:
List(CStringstrsourcename)
{
CInternetSession*psession;//新建一个Internet会话
CFtpConnection*pconnect;//建立一个用于ftp连接的指针
CFtpFileFind*pfilefind;//建立一个用于文件查询的指针
CStringstrfilename;
pconnect=NULL;
pfilefind=NULL;
BOOLbContinue;
psession=newCInternetSession();//初始化internet会话对象
try{
pconnect=psession->GetFtpConnection(m_strServername,m_strUsername,m_strPwd);//通过internet会话对象调用函数创建ftp连接
}
catch(CInternetException*e)
{
e->Delete();
pconnect=NULL;
}
if(pconnect!
=NULL)
{
pfilefind=newCFtpFileFind(pconnect);//初始化文件查找指针
if(strsourcename=="")
{
bContinue=pfilefind->FindFile("*");//如果为初始路径查找全部文件,返回值为bool型
}
else
bContinue=pfilefind->FindFile(strsourcename);//查找相应路径文件
if(!
bContinue)
{
pfilefind->Close();
pfilefind=NULL;
}
while(bContinue)
{
bContinue=pfilefind->FindNextFileA();//继续查找下一个文件
strfilename=pfilefind->GetFileName();//获得文件名
if(pfilefind->IsDirectory())//判断是否为目录
strfilename="["+strfilename+"]";//如果为目录则加上中括号显示
m_listFile.AddString(strfilename);//将文件名加入到列表框中
}
if(pfilefind!
=NULL)
{
pfilefind->Close();
pfilefind=NULL;
}
}
deletepfilefind;
if(pconnect!
=NULL)
{
pconnect->Close();
deletepconnect;
}
deletepsession;
}
添加响应单击列表框的消息效应voidCFtpDlg:
:
OnDblclkListFile(),用于获取列表框文件的信息。
具体代码:
voidCFtpDlg:
:
OnSelchangeListFile()
{
//TODO:
在此添加控件通知处理程序代码
m_btnquery.EnableWindow(TRUE);
m_btnremove.EnableWindow(TRUE);
m_btnDownload.EnableWindow(TRUE);
}
添加响应双击列表框的消息响应voidCFtpDlg:
:
OnSelchangeListFile(),用于双击列表框时获取信息。
代码如下:
voidCFtpDlg:
:
OnDblclkListFile()
{
//TODO:
在此添加控件通知处理程序代码
CStringstrfilename;
intsel=m_listFile.GetCurSel();//获得双击文件在列表框中的位置索引
m_listFile.GetText(sel,strfilename);//调用gettext获得文件名并将其存入字符串中
intlength=strfilename.GetLength();//获取文件名的长度
if(strfilename.GetAt(0)=='[')//判断是否为文件夹
{
strfilename=strfilename.Mid(1,length-2);
strflag+=strfilename+"/";//保存新的路径
}
while(m_listFile.GetCount()!
=0)m_listFile.DeleteString(0);//清空列表框
List(strflag);//调用列表框查询新路径下的文件
}
添加下载文件函数,用于下载服务器端的文件BOOLCFtpDlg:
:
Download(CStringstrfilename,CStringstrpathname)。
BOOLCFtpDlg:
:
Download(CStringstrfilename,CStringstrpathname)
{
UpdateData(TRUE);
CInternetSession*psession;
CFtpConnection*pconnect;
pconnect=NULL;
psession=newCInternetSession(AfxGetAppName(),1,PRE_CONFIG_INTERNET_ACCESS);
try{
pconnect=psession->GetFtpConnection(m_strServername,m_strUsername,m_strPwd);
}
catch(CInternetException*e)
{
e->Delete();
pconnect->Close();
returnFALSE;
}
if(pconnect!
=NULL)
{
if(!
pconnect->GetFile(strfilename,strpathname))//调用getfile文件下载文件
{
pconnect->Close();
deletepconnect;
deletepsession;
returnFALSE;
}
}
if(pconnect!
=NULL)
{
pconnect->Close();
deletepconnect;
}
deletepsession;
returnTRUE;
}
添加上传文件函数,用于上传文件到服务器端BOOLCFtpDlg:
:
Upload(CStringstrpathname,CStringstrfilename)。
代码如下:
BOOLCFtpDlg:
:
Upload(CStringstrpathname,CStringstrfilename)
{
UpdateData(TRUE);
CInternetSession*psession;
CFtpConnection*pconnect;
pconnect=NULL;
psession=newCInternetSession(AfxGetAppName(),1,PRE_CONFIG_INTERNET_ACCESS);
try{
pconnect=psession->GetFtpConnection(m_strServername,m_strUsername,m_strPwd);
}
catch(CInternetException*e)
{
e->Delete();
pconnect->Close();
returnFALSE;
}
if(pconnect!
=NULL)
{
if(!
pconnect->PutFile(strpathname,strfilename))//上传文件
{
pconnect->Close();
deletepconnect;
deletepsession;
returnFALSE;
}
}
if(pconnect!
=NULL)
{
p