资源描述
《计算机网络》课程设计
课题名称 FTP客户机搭建
学院 信息工程学院
专业 网络工程
班级
学号
姓名
目录和索引
一、需求分析------------------------------------------2
1、功能需求
2、开发环境与工具
3、所需要知识
二、知识理解 -----------------------------------------2
1、FTP实现的基本原理
(1)概要
(2)上传和下载
(3)用户FTP和匿名FTP
(4)ASCII和Binary
(5)Port和Passive
三、完成进度-----------------------------------------3
1、已完成部分
2、未完成部分
3、还需改善的部分
四、FTP服务工作过程---------------------------------4
五、详细设计-----------------------------------------5
1、CFtpDlg类的一些函数定义………………………………………………5
2、CFtpOperate的一些函数定义……………………………………………17
六、测试结果----------------------------------------29
七、用户手册----------------------------------------32
八、实验总结----------------------------------------32
FTP客户端程序
一、需求分析
1、功能需求
(1)实现一个图形用户界面的FTP客户端,保证文件的安全传输和存储。
(2)提供登录界面,上传下载界面、帮助界面、关于界面。
(3)通过输入服务器地址、用户名和密码,可以实现远程FTP主机的登录。
(4)提供本地文件和文件夹的上传功能,可对FTP主机文件进行下载和删除文件。
(5)提供对本地目录的读取与返回,能正确列出文件和文件夹,在没有登录服务器前可以作为一个简单的文件查询工具对本地文件进行查询。
(6)帮助页面可以对用户提供使用说明。
(7)关于界面包含设计者的信息。
(9)要求开发出的FTP客户端符合标准FTP协议规范,支持ASCII传输模式和二进制数据传输模式
(10)FTP的两种工作模式的选择Port模式(主动)和Passive模式(被动)
2、开发环境与工具
(1)使用的IDE:使用VC++6.0作为开发环境IDE
(2)使用的语言:C++
(3)使用的开发包:使用MFC和WinInet
(4)开发平台:Windows 7
3、所需要知识
(1)计算机网络的基本知识
(2)了解FTP基本实现原理
(2)使用VC++6.0IDE进行MFC程序开发的基本知识
(3)熟悉WinInet中属于FTP部分的操作
(4)熟悉文件或文件夹操作
(5)熟悉控件的操作,如在List Ctrol添加图片(浏览文件或文夹的图标)
二、知识理解
1、FTP实现的基本原理
(1)概要
Internet是一个非常复杂的计算机环境, Internet上的计算机已有上千万台,而这些计算机可能运行不同的操作系统,有运行Unix的服务器,也有运行Dos、Windows的PC机等等,而各种操作系统之间的文件交流问题,需要建立一个统一的文件传输协议,这就是所谓的FTP。基于不同的操作系统有不同的FTP应用程序,而所有这些应用程序都遵守同一种协议,这样用户就可以把自己的文件传送给别人,或者从其它的用户环境中获得文件。
FTP也是一个客户机/服务器系统。用户通过一个支持FTP协议的客户机程序,连接到在远程主机上的FTP服务器程序。用户通过客户机程序向服务器程序发出命令,服务器程序执行用户所发出的命令,并将执行的结果返回到客户机。使用FTP时必须首先登录,在远程主机上获得相应的权限以后,方可下载或上传文件。
(2)上传和下载
"下载"文件就是从远程主机拷贝文件至自己的计算机上;
"上传"文件就是将文件从自己的计算机中拷贝至远程主机上
(3)用户FTP和匿名FTP
用户FTP: 种方式为已在FTP服务器上建立了特定帐号的用户使用,需要合法的用户名和密码才能登录到远程计算机传输文件。
匿名FTP:用户作为“anonymous” 登录到FTP服务器,不需要有自己的用户名和密码。
(4)ASCII和Binary
ASCII: 文本传输器使用ASCII字符,并由回车键和换行符分开
Binary:二进制不用转换或格式化就可传字符,二进制模式比文本模式更快,并且可以传输所有ASCII值,所以系统管理员一般将FTP设置成二进制模式。
(5)Port和Passive
Port模式( 主动):FTP 客户端首先和FTP服务器的TCP 21端口建立连接,通过这个通道发送命令,客户端需要接收数据的时候在这个通道上发送PORT命令。 PORT命令包含了客户端用什么端口接收数据。在传送数据的时候,服务器端通过自己的TCP 20端口连接至客户端的指定端口发送数据。 FTP server必须和客户端建立一个新的连接用来传送数据。
Passive模式(被动):Passive模式在建立控制通道的时候和Standard模式类似,但建立连接后发送的不是Port命令,而是Pasv命令。FTP服务器收到Pasv命令后,随机打开一个高端端口(端口号大于1024)并且通知客户端在这个端口上传送数据的请求,客户端连接FTP服务器此端口,然后FTP服务器将通过这个端口进行数据的传送,这个时候FTP server不再需要建立一个新的和客户端之间的连接。
三、完成进度
1、已完成部分
(1)实现一个图形用户界面的FTP客户端,保证文件的安全传输和存储。
(2)提供登录界面,上传下载界面、帮助界面、关于界面
(3)通过输入服务器地址、用户名和密码,可以实现远程FTP主机的登录。
(4)提供本地文件上传功能,可对FTP主机文件进行下载和删除文件。
(5)提供对本地目录的读取与返回,能正确列出文件和文件夹,在没有登录服务器前可以作为一个简单的文件查询工具对本地文件进行查询。
(6)帮助页面可以对用户提供使用说明。
(7)关于界面包含设计者的信息(帮助界面和关于界面整合在一起)。
(9)支持ASCII传输模式和二进制数据传输模式,外加自动选择的模式
(10)FTP的两种工作模式的选择Port模式(主动)和Passive模式(被动)
(11)提供用户操作的状态信息输出
2、未完成部分
只提供了本地文件的上传功能,暂时不能提供文件夹的上传功能,由于当初没有使用多线程对服务器端进行操作,若上传或下载的文件过大,会导致界面陷入长时间的不响应中。由于时间问题,就不再进行多线程的扩充,也就不提供文件夹的上传功能。
3、还需改善的部分
(1)使用多线程进行操作
(2)提供文件夹上传和文件夹下载功能
(3)改进界面,提供更方便的操作
(4)增加上传和下载的队列
(5)同时可连接多个FTP服务器
(6)改善提示信息
(7)账户。密码等用户资料在本地加密后保存
(8)增加更多的功能,如下载完成后关机等
(9)等………
四、FTP服务工作程
五、详细设计
(1)CFtpDlg类的一些函数定义
BOOL CFtpDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Add "About..." menu item to system menu.
// IDM_ABOUTBOX must be in the system command range.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
SetIcon(m_hIcon, TRUE);
SetIcon(m_hIcon, FALSE);
m_ctrBinary.SetCheck(1);
m_ctrActive.SetCheck(1);
m_editPort.SetWindowText("21");
bBinary1 = 1; // 使用二进制
bPassive1 = 0; // 使用主动
myPort = 21;
m_imgList.Create(20,20,ILC_COLOR32,0,0); // 创建图像列表
m_imgList.SetBkColor(RGB(255,255,255)); // 文件夹图标
hIconFold = ::LoadIcon(AfxGetResourceHandle(),MAKEINTRESOURCE(IDI_FOLDER));
// 文件图标
hIconFile = ::LoadIcon(AfxGetResourceHandle(),MAKEINTRESOURCE(IDI_FILE));
m_imgList.Add(hIconFold);
m_imgList.Add(hIconFile);
m_ctrlLocalFile.SetImageList(&m_imgList,LVSIL_SMALL); // 关联
m_ctrlServerFile.SetImageList(&m_imgList,LVSIL_SMALL); // 关联
m_editServer.SetWindowText("ftp:// ");
m_editName.SetWindowText("");
m_editPassword.SetWindowText("");
m_btnCon.EnableWindow(TRUE);
m_btnClo.EnableWindow(FALSE);
m_ctrlLocalFile.SetExtendedStyle(LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES);
m_ctrlServerFile.SetExtendedStyle(LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES);
m_ctrlLocalFile.InsertColumn(0,"文件名",LVCFMT_LEFT,140,0);//设置列
m_ctrlLocalFile.InsertColumn(1,"文件类型",LVCFMT_LEFT,100,1);
m_ctrlLocalFile.InsertColumn(2,"修改日期",LVCFMT_LEFT,100,2);
m_ctrlServerFile.InsertColumn(0,"文件名",LVCFMT_LEFT,140,0);//设置列
m_ctrlServerFile.InsertColumn(1,"文件类型",LVCFMT_LEFT,100,1);
m_ctrlServerFile.InsertColumn(2,"修改日期",LVCFMT_LEFT,100,2);
// 添加硬盘盘符
size_t szAllDriveStrings=::GetLogicalDriveStrings(0,NULL);
TCHAR *pDriveStrings=new TCHAR[szAllDriveStrings+sizeof(_T(" "))];
GetLogicalDriveStrings(szAllDriveStrings,pDriveStrings);
size_t szDriveString=::strlen(pDriveStrings);
while(szDriveString>0)
{
m_ctrlLocal.AddString(pDriveStrings);
pDriveStrings+=szDriveString+1;
szDriveString=::strlen(pDriveStrings);
}
int index = m_ctrlLocal.FindString(0,"c:\\");
m_ctrlLocal.SetCurSel(index);
m_strLocPath = "c:\\"; // 初始化为c盘
ListLocFile();
cFtpOpr.setEidt(&m_ediMessage);
return TRUE; // return TRUE unless you set the focus to a control
}
void CFtpDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialog::OnSysCommand(nID, lParam);
}
}
void CFtpDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
}
HCURSOR CFtpDlg::OnQueryDragIcon()
{
return (HCURSOR) m_hIcon;
}
// 连接服务器
void CFtpDlg::OnBtnConnect()
{
// TODO: Add your control notification handler code here
m_editServer.GetWindowText(m_strServer); // 记录FTP服务器地址
CString strtemp;
m_editPort.GetWindowText(strtemp);
myPort = ::atoi(strtemp); // 获得设置的端口号
int i;
if (bAnony == 0)
{// 不使用匿名
m_editName.GetWindowText(m_strName); // 记录FTP登陆用户名
m_editPassword.GetWindowText(m_strPassword); // 记录FTP登陆用户密码
i = cFtpOpr.set(m_strServer,m_strName,m_strPassword);
}
else
{// 使用匿名
CString strNameTemp;
m_editName.GetWindowText(strNameTemp); // 匿名登陆的用户名
i = cFtpOpr.set(m_strServer,strNameTemp,"");
}
if (i)
{// 设置成功,打开连接
if (cFtpOpr.OpenConnection())
{// 连接成功
m_btnClo.EnableWindow(TRUE);
m_btnCon.EnableWindow(FALSE);
UpdateServerFile();// 更新服务器的文件显示
m_ctrlServer.ResetContent();
CString temp;
cFtpOpr.GetPath(temp);
m_ctrlServer.AddString((LPSTR)(LPCTSTR)temp);
m_ctrlServer.SetCurSel(0);
m_chkAnony.EnableWindow(FALSE);
m_ctrActive.EnableWindow(FALSE);
CButton *temp2 =(CButton*)GetDlgItem(IDC_PASSIVE);
temp2->EnableWindow(FALSE);
m_editPort.EnableWindow(FALSE);
}
else
{
// 连接失败
}
}
}
void CFtpDlg::OnBtnClose()
{// 关闭连接
if (cFtpOpr.CloseConnection())
{// 关闭成功
m_btnClo.EnableWindow(FALSE);
m_btnCon.EnableWindow(TRUE);
m_ctrlServerFile.DeleteAllItems();
m_ctrlServer.ResetContent();
m_ctrActive.EnableWindow(TRUE);
CButton *temp2 =(CButton*)GetDlgItem(IDC_PASSIVE);
temp2->EnableWindow(TRUE);
m_editPort.EnableWindow(TRUE);
m_chkAnony.EnableWindow(TRUE);
}
}
// 双击本地文件列表控件中的选项
void CFtpDlg::OnDblclkListLocalfile(NMHDR* pNMHDR, LRESULT* pResult)
{
// TODO: Add your control notification handler code here
POSITION p=m_ctrlLocalFile.GetFirstSelectedItemPosition();
if (p == NULL)
{
return;
}
//获取刚选取的位置的下标(从0开始的)
int index = m_ctrlLocalFile.GetNextSelectedItem(p);
//获得选中的内容
//得到第index行.第0列的内容(下标从0开始)
CString FirstColumn=m_ctrlLocalFile.GetItemText(index,0);
CString SecondColumn = m_ctrlLocalFile.GetItemText(index,1);
if (index == 0) // 返回上层目录
{
int k = m_strLocPath.GetLength() - 1;
if (m_strLocPath.Right(2) == ":\\")
{
return;
}
// 删除当层的项目
int ix = m_ctrlLocal.FindString(0,m_strLocPath);
if (ix != CB_ERR)
{
m_ctrlLocal.DeleteString(ix);
}
for (int j = k -1; j >= 2;--j)
{
if (m_strLocPath.GetAt(j) == '\\')
{
m_strLocPath = m_strLocPath.Left(j+1);
break;
}
}
ListLocFile();
*pResult = 0;
return;
}
if (SecondColumn=="文件夹")
{
CString strTemp = FirstColumn;
m_strLocPath += strTemp + '\\';
ListLocFile(); // 更新本地磁盘文件显示
}
else if (SecondColumn=="文件")
{// 点到的是文件,进行上传
if (cFtpOpr.ReStatus()==2)
{
cFtpOpr.PutFtpFile(m_strLocPath + FirstColumn,FirstColumn);
UpdateServerFile();// 更新服务器的文件显示
}
}
*pResult = 0;
}
void CFtpDlg::OnDblclkListServerfile(NMHDR* pNMHDR, LRESULT* pResult)
{
// TODO: Add your control notification handler code here
//获取选中的的一个位置
POSITION p=m_ctrlServerFile.GetFirstSelectedItemPosition();
if (p == NULL)
{
return;
}
//获取刚选取的位置的下标(从0开始的)
int index = m_ctrlServerFile.GetNextSelectedItem(p);
//获得选中的内容,得到第index行.第0列的内容(下标从0开始)
CString FirstColumn=m_ctrlServerFile.GetItemText(index,0);
CString SecondColumn = m_ctrlServerFile.GetItemText(index,1);
CStringArray ServName;
int nFileNumber=0;
if (index == 0) // 返回上层目录
{
if (cFtpOpr.setBackPath() == 0)
{
*pResult = 0;
return;
}
UpdateServerFile();// 更新服务器的文件显示
CString temp;
m_ctrlServer.ResetContent();
cFtpOpr.GetPath(temp);
m_ctrlServer.AddString((LPSTR)(LPCTSTR)temp);
m_ctrlServer.SetCurSel(0);
*pResult = 0;
return;
}
if (SecondColumn=="文件夹")
{
if (cFtpOpr.setNextPath(FirstColumn) == 0)
{
*pResult = 0;
return;
}
UpdateServerFile();// 更新服务器的文件显示
CString temp;
m_ctrlServer.ResetContent();
cFtpOpr.GetPath(temp);
m_ctrlServer.AddString((LPSTR)(LPCTSTR)temp);
m_ctrlServer.SetCurSel(0);
}
else if (SecondColumn=="文件")
{// 点到的是文件,进行下载
cFtpOpr.GetFtpFile(FirstColumn,m_strLocPath);
ListLocFile();
}
*pResult = 0;
}
// 将本地文件列表出来
void CFtpDlg::ListLocFile()
{
m_ctrlLocalFile.DeleteAllItems();
int ix = m_ctrlLocal.FindString(0,m_strLocPath);
if (ix == CB_ERR)
{
int iy = m_ctrlLocal.GetCount();
m_ctrlLocal.SetCurSel(m_ctrlLocal.AddString(m_strLocPath));
}
else
{
m_ctrlLocal.SetCurSel(m_ctrlLocal.SetCurSel(ix));
}
int k = 0;
m_ctrlLocalFile.InsertItem(0,"...上层目录");
char * lpPath = (LPSTR)(LPCTSTR)m_strLocPath;
char szFind[300];
WIN32_FIND_DATA FindFileData;
strcpy(szFind,lpPath);
strcat(szFind,"*.*");
HANDLE hFind=::FindFirstFile(szFind,&FindFileData);
while(TRUE)
{
if(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
CString str = FindFileData.cFileName;
if (str != '.' && str != "..")
{
LVITEM lvitem;
lvitem.mask = LVIF_IMAGE|LVIF_TEXT;
lvitem.iItem = k+1;
lvitem.pszText = (LPSTR)(LPCTSTR)str;
lvitem.iImage = 0;
lvitem.iSubItem =0;
m_ctrlLocalFile.InsertItem(&lvitem);
m_ctrlLocalFile.SetItemText(k+1,1,"文件夹");
++k;
}
}
else
{
// 文件
LVITEM lvitem;
lvitem.mask = LVIF_IMAGE|LVIF_TEXT;
lvitem.iItem = k+1;
lvitem.pszText = FindFileData.cFileName;
lvitem.iImage = 1;
lvitem.iSubItem = 0;
m_ctrlLocalFile.InsertItem(&lvitem);
m_ctrlLocalFile.SetItemText(k+1,1,"文件");
++k;
}
if(!FindNextFile(hFind,&FindFileData))break;
}
FindClose(hFind);
}
// 选择了本地文件的组合框中的不同项目
void CFtpDlg::OnSelchangeComboboxexLocal()
{
m_ctrlLocal.SetCurSel(m_ctrlLocal.GetCurSel());
m_ctrlLocal.GetWindowText(m_strLocPath);
m_ctrlLocal.ResetContent();
// 添加硬盘盘符
size_t szAllDriveStrings=::GetLogicalDriveStrings(0,NULL);
TCHAR *pDriveStrings=new TCHAR[szAllDriveStrings+sizeof(_T(" "))];
GetLogicalDriveStrings(szAllDriveStrings,pDriveStrings);
size_t szDriveString=::strlen(pDriveStrings);
while(szDriveString>0)
{
m_ctrlLocal.AddString(pDriveStrings);
pDriveStrings+=szDriveString+1;
szDriveString=::strlen(pDriveStrings);
}
ListLocFile();
}
// 点击了ASCII单选按钮
void CFtpDlg::OnAscii()
{
bBinary1 = 0;
}
// 点击了二进制单选按钮
void CFtpDlg::OnBinary()
{
bBinary1 = 1; // 使用二进制
}
// 自动选择二进制或ASCII单选按钮
void CFtpDlg::OnAuto()
{
bBinary1 = 2; // 自动
}
// 主动方式单选按钮
void CFtpDlg::OnActive()
{
bPassive1 = 0;
}
// 被动方式单选按钮
void CFtpDlg::OnPassive()
{
bPassive1 = 1;
}
// 上传
void CFtpDlg::OnBtnup()
{
POSITION p=m_ctrlLocalFile.GetFirstSelectedItemPosition();
if (p == NULL)
{
return;
}
//获取刚选取的位置的下标(从0开始的)
int index = m_ctrlLocalFile.GetNextSelectedItem(p);
//获得选中的内容
//得到第index行.第0列的内容(下标从0开始)
CString FirstColumn=m_ctrlLocalFile.GetItemText(index,0);
CString SecondColumn = m_ctrlLocalFile.GetItemText(index,1);
if (SecondColumn=="文件夹")
{
CTime CurrentTime=CTime::GetCurrentTime();
CString strTime;
strTime.Format("%d/%d/%d %d:%d:%d ",CurrentTime.GetYear(),CurrentTime.GetMonth(),
CurrentTime.GetDay(),CurrentTime.GetHour(), CurrentTime.GetMinute(),
CurrentTime.GetSecond());
strTime += "暂不支持上传文件夹!\r\n";
int nLength = m_ediMessage.SendMessage(WM_GETTEXTLENGTH);
m_ediMessage.SetSel(nLength, nLength);
m_ediMessage.ReplaceSel(strTime);
return;
}
else if (SecondColumn=="文件")
{
// 点到的是文件,进行上传
if (cFtpOpr.ReStatus()==2)
{
cFtpOpr.PutFtpFile(m_strLocPath + FirstColumn,FirstColumn);
UpdateServerFile();// 更新服务器的文件显示
}
}
}
//下载
void CFtpDlg::OnBtndown()
{
// TODO: Add your control notification handler code here
POSITION p=m_ctrlServerFile.GetFirstSelectedItemPosition();
if (p == NULL)
{
return;
}
//获取刚选取的位置的下标(从0开始的)
int index = m_ctrlServerFile.GetNextSelectedItem(p);
//获得选中的内容
//得到第index行.第0列的内容(下标从0开始)
CString FirstColumn=m_ctrlServerFile.GetItemText(index,0);
CString SecondColumn = m_ctrlSer
展开阅读全文