win32FTP程序设计
掌握socket基于事件机制的网络程序设计,掌握多线程技术的FTP Server端设计方法,掌握FTP标准基本协议及其程序的实现,掌握文件内容的网络传输设计方法。
利用CFtpServer类接收和解析客户端命令,编写FTP客户端程序,服务器端使用多线程,实现多用户同时登录管理;
利用CFtpConnection和CInternetSession类,编写FTP客户端,实现简单文件操作功能。
- FTP服务器实现
1.服务器窗口界面设计
服务器主界面
2.功能实现:
(1)初始化FTP并启动监听
BOOL CFTPServer::Start()
{
if (m_bRunning)
return FALSE;
// create dummy window for message routing
if (!CWnd::CreateEx(0, AfxRegisterWndClass(0), "FTP Server Notification Sink", WS_POPUP, 0,0,0,0, NULL, 0))
{
AddTraceLine(0, "Failed to create notification window.");
return FALSE;
}
// created the listen socket
if (m_ListenSocket.Create(m_nPort))
{
// start listening
if (m_ListenSocket.Listen())
{
m_ListenSocket.m_pWndServer = this;
m_bRunning = TRUE;
SetTimer(1, m_nStatisticsInterval, NULL);
AddTraceLine(0, "FTP Server started on port %d.", m_nPort);
return TRUE;
}
}
AddTraceLine(0, "FTP Server failed to listen on port %d.", m_nPort);
// destroy notification window
if (IsWindow(m_hWnd))
DestroyWindow();
m_hWnd = NULL;
return FALSE;
}
(2)停止FTP
通知各线程停止监听,关闭进程,释放连接,实现代码如下
void CFTPServer::Stop()
{
if (!m_bRunning)
return;
// stop statistics timer
KillTimer(1);
m_bRunning = FALSE;
m_ListenSocket.Close();
CConnectThread* pThread = NULL;
// close all running threads
do
{
m_CriticalSection.Lock();
POSITION pos = m_ThreadList.GetHeadPosition();
if (pos != NULL)
{
pThread = (CConnectThread *)m_ThreadList.GetAt(pos);
m_CriticalSection.Unlock();
// save thread members
int nThreadID = pThread->m_nThreadID;
HANDLE hThread = pThread->m_hThread;
AddTraceLine(0, "[%u] Shutting down thread...", nThreadID);
// tell thread to stop
pThread->SetThreadPriority(THREAD_PRIORITY_HIGHEST);
pThread->PostThreadMessage(WM_QUIT,0,0);
// wait for thread to end, while keeping the messages pumping (max 5 seconds)
if (WaitWithMessageLoop(hThread, 5000) == FALSE)
{
// thread doesn't want to stopped
AddTraceLine(0, "[%u] Problem while killing thread.", nThreadID);
// don't try again, so remove
m_CriticalSection.Lock();
POSITION rmPos = m_ThreadList.Find(pThread);
if (rmPos != NULL)
m_ThreadList.RemoveAt(rmPos);
m_CriticalSection.Unlock();
}
else
{
AddTraceLine(0, "[%u] Thread successfully stopped.", nThreadID);
}
}
else
{
m_CriticalSection.Unlock();
pThread = NULL;
}
}
while (pThread != NULL);
AddTraceLine(0, "FTP Server stopped.");
if (IsWindow(m_hWnd))
DestroyWindow();
m_hWnd = NULL;
}
(3)账号操作
用户账号操作包括:添加,编辑、删除和保存,具体实现代码如下:
//添加账号
void CUserAccountPage::OnAddUser()
{
CAddUserDlg dlg;
if (dlg.DoModal() == IDOK)
{
for (int i=0; i<m_UsersList.GetItemCount(); i++)
{
CString strName;
strName = m_UsersList.GetItemText(i, 0);
if (strName.CompareNoCase(dlg.m_strName) == 0)
{
AfxMessageBox("Sorry, this user already exists!");
return;
}
}
CUser user;
user.m_strName = dlg.m_strName;
user.m_strPassword = "";
int nItem = m_UsersList.InsertItem(0, user.m_strName, 0);
if (nItem <= m_nPreviousIndex)
m_nPreviousIndex++;
// add home directory item
user.m_bAllowCreateDirectory = FALSE;
user.m_bAllowDelete = FALSE;
user.m_bAllowDownload = TRUE;
user.m_bAllowRename = FALSE;
user.m_bAllowUpload = FALSE;
user.m_strHomeDirectory = "";
int index = m_UserArray.Add(user);
m_UsersList.SetItemData(nItem, index);
m_UsersList.SetItemState(nItem, LVIS_SELECTED | LVIS_FOCUSED , LVIS_SELECTED | LVIS_FOCUSED);
OnSelchangeUserlist();
// update user manager
theServer.m_UserManager.UpdateUserList(m_UserArray);
SetModified();
// launch directory browser
PostMessage(WM_COMMAND, IDC_BROWSE);
}
}
//更改用户名
void CUserAccountPage::OnEditUser()
{
// get selected user
int nSelIndex = m_UsersList.GetNextItem(-1, LVNI_ALL | LVNI_SELECTED);
if(nSelIndex == -1)
return;
int nUserIndex = m_UsersList.GetItemData(nSelIndex);
CAddUserDlg dlg;
dlg.m_strTitle = "修改";
dlg.m_strName = m_UserArray[nUserIndex].m_strName;
if (dlg.DoModal() == IDOK)
{
// check if user already exists
for (int i=0; i<m_UsersList.GetItemCount(); i++)
{
if (i != nSelIndex)
{
CString strName;
strName = m_UsersList.GetItemText(i, 0);
if (strName.CompareNoCase(dlg.m_strName) == 0)
{
AfxMessageBox("Sorry, this user already exists!");
return;
}
}
}
m_UserArray[nUserIndex].m_strName = dlg.m_strName;
m_UsersList.DeleteItem(nSelIndex);
nSelIndex = m_UsersList.InsertItem(0, dlg.m_strName, 0);
m_UsersList.SetItemData(nSelIndex, nUserIndex);
m_UsersList.SetItemState(nSelIndex, LVIS_SELECTED | LVIS_FOCUSED , LVIS_SELECTED | LVIS_FOCUSED);
m_nPreviousIndex = nSelIndex;
OnSelchangeUserlist();
// update user manager
theServer.m_UserManager.UpdateUserList(m_UserArray);
SetModified(FALSE);
}
}
//更改用户目录
void CUserAccountPage::OnBrowse()
{
CString strDir = BrowseForFolder(m_hWnd, "Select a home directory:", BIF_RETURNONLYFSDIRS);
if (!strDir.IsEmpty())
{
m_strHomeDirectory = strDir;
UpdateData(FALSE);
}
}
//删除账号
void CUserAccountPage::OnDelUser()
{
int nSelIndex = m_UsersList.GetNextItem(-1, LVNI_ALL | LVNI_SELECTED);
if(nSelIndex == -1)
return;
CString strText;
strText.Format("Are you sure you want to delete '%s'?", m_UsersList.GetItemText(nSelIndex, 0));
if (MessageBox(strText, "FTP Server", MB_YESNO | MB_ICONQUESTION) != IDYES)
{
return;
}
int nUserIndex = m_UsersList.GetItemData(nSelIndex);
// remove user from array
m_UserArray.RemoveAt(nUserIndex);
m_nPreviousIndex = -1;
// update item data values
m_UsersList.SetRedraw(FALSE);
m_UsersList.DeleteAllItems();
// update user list
for (int i=0; i < m_UserArray.GetSize(); i++)
{
int nIndex = m_UsersList.InsertItem(0, m_UserArray[i].m_strName, 0);
m_UsersList.SetItemData(nIndex, i);
}
m_UsersList.SetRedraw(TRUE);
// update user manager
theServer.m_UserManager.UpdateUserList(m_UserArray);
SetModified(FALSE);
m_UsersList.SetItemState(nSelIndex-1, LVIS_SELECTED | LVIS_FOCUSED , LVIS_SELECTED | LVIS_FOCUSED);
OnSelchangeUserlist();
}
//保存当前修改
BOOL CUserAccountPage::UpdateAccount(int nSelIndex)
{
if (nSelIndex == -1)
{
// get selected user
nSelIndex = m_UsersList.GetNextItem(-1, LVNI_ALL | LVNI_SELECTED);
}
if (nSelIndex != -1)
{
UpdateData();
int nUserIndex = m_UsersList.GetItemData(nSelIndex);
m_UserArray[nUserIndex].m_strPassword = m_strPassword;
m_UserArray[nUserIndex].m_bAccountDisabled = m_bDisableAccount;
// check if it's a valid directory
if (GetFileAttributes(m_strHomeDirectory) == 0xFFFFFFFF)
{
MessageBox("Please enter a valid home directory", "FTP Server", MB_OK | MB_ICONEXCLAMATION);
GetDlgItem(IDC_HOME_DIRECTORY)->SetFocus();
m_UsersList.SetItemState(m_nPreviousIndex, LVIS_SELECTED | LVIS_FOCUSED , LVIS_SELECTED | LVIS_FOCUSED);
return FALSE;
}
m_UserArray[nUserIndex].m_strHomeDirectory = m_strHomeDirectory;
m_UserArray[nUserIndex].m_bAllowCreateDirectory = m_bAllowCreateDirectory;
m_UserArray[nUserIndex].m_bAllowDelete = m_bAllowDelete;
m_UserArray[nUserIndex].m_bAllowDownload = m_bAllowDownload;
m_UserArray[nUserIndex].m_bAllowRename = m_bAllowRename;
m_UserArray[nUserIndex].m_bAllowUpload = m_bAllowUpload;
// update user manager
theServer.m_UserManager.UpdateUserList(m_UserArray);
return TRUE;
}
return FALSE;
}
(4)查看在线用户及其使用的线程号
在线用户显示页面主要代码如下:
BOOL COnlineUsersPage::OnInitDialog()
{
CDialog::OnInitDialog();
m_OnlineUsers.InsertColumn(0, "ThreadID");
m_OnlineUsers.InsertColumn(1, "Username");
m_OnlineUsers.InsertColumn(2, "IP Adress");
m_OnlineUsers.InsertColumn(3, "Login Time");
DWORD dwStyle = m_OnlineUsers.GetExtendedStyle();
dwStyle |= LVS_EX_FULLROWSELECT;
m_OnlineUsers.SetExtendedStyle(dwStyle);
return TRUE;
}
void COnlineUsersPage::OnSize(UINT nType, int cx, int cy)
{
CDialog::OnSize(nType, cx, cy);
if (IsWindow(::GetDlgItem(m_hWnd, IDC_ONLINE_USERS)))
{
CRect rect;
GetClientRect(rect);
m_OnlineUsers.MoveWindow(rect);
m_OnlineUsers.SetColumnWidth(0, 0);
m_OnlineUsers.SetColumnWidth(1, rect.Width()/3-2);
m_OnlineUsers.SetColumnWidth(2, rect.Width()/3-2);
m_OnlineUsers.SetColumnWidth(3, rect.Width()/3-2);
}
}
void COnlineUsersPage::AddUser(DWORD nThreadID, LPCTSTR lpszName, LPCTSTR lpszAddress)
{
CString strThreadID;
strThreadID.Format("%d", nThreadID);
LVFINDINFO info;
info.flags = LVFI_PARTIAL|LVFI_STRING;
info.psz = (LPCTSTR)strThreadID;
int nIndex = m_OnlineUsers.FindItem(&info);
if (nIndex == -1)
{
nIndex = m_OnlineUsers.InsertItem(0, strThreadID);
}
m_OnlineUsers.SetItemText(nIndex, 1, lpszName);
m_OnlineUsers.SetItemText(nIndex, 2, lpszAddress);
m_OnlineUsers.SetItemText(nIndex, 3, CTime::GetCurrentTime().Format("%H:%M:%S"));
}
void COnlineUsersPage::RemoveUser(DWORD nThreadID)
{
LVFINDINFO info;
CString strThreadID;
strThreadID.Format("%d", nThreadID);
info.flags = LVFI_PARTIAL|LVFI_STRING;
info.psz = (LPCTSTR)strThreadID;
int nIndex = m_OnlineUsers.FindItem(&info);
if (nIndex != -1)
{
m_OnlineUsers.DeleteItem(nIndex);
}
}
void COnlineUsersPage::OnContextMenu(CWnd* pWnd, CPoint point)
{
// get selected user
int nIndex = m_OnlineUsers.GetNextItem(-1, LVNI_ALL | LVNI_SELECTED);
if(nIndex == -1)
return;
CMenu menu;
menu.LoadMenu(MAKEINTRESOURCE(IDR_ONLINE_MENU));
menu.GetSubMenu(0)->TrackPopupMenu(0, point.x, point.y, this, NULL);
}
void COnlineUsersPage::OnKickUser()
{
int nIndex = m_OnlineUsers.GetNextItem(-1, LVNI_ALL | LVNI_SELECTED);
while (nIndex != -1)
{
CString strThreadID = m_OnlineUsers.GetItemText(nIndex, 0);
PostThreadMessage(atoi(strThreadID), WM_QUIT, 0 ,0);
nIndex = m_OnlineUsers.GetNextItem(nIndex, LVNI_ALL | LVNI_SELECTED);
}
}
void COnlineUsersPage::OnCancel()
{
// CDialog::OnCancel();
}
void COnlineUsersPage::OnOK()
{
// CDialog::OnOK();
}
- FTP客户端实现
为检验FTP客户端的可用性和进一步掌握FTP标准基本协议及文件内容的网络传输设计方法,我实现了一个简单的FTP客户端程序。
1.客户端窗口界面设计
FTP客户端程序主界面
2.功能实现:
(1)服务器的连接与断开
void CFTPClientDlg::OnButtonConnect()
{
// TODO: Add your control notification handler code here
UpdateData(TRUE);
if(!m_ftpConnection){
if(m_str_address!=""){
m_ftpConnection=m_internetSession.GetFtpConnection(m_str_address,m_str_username,m_str_password);
if(m_ftpConnection){
m_ftpConnection->GetCurrentDirectory(m_str_server_dir);
UpdateData(FALSE);
LoadFileList();
m_btn_connect.SetWindowText("断开");
}
}
}
else{
m_ftpConnection->Close();
delete m_ftpConnection;
m_ftpConnection=NULL;
m_btn_connect.SetWindowText("连接");
m_str_server_dir="";
m_listbox_files.ResetContent();
UpdateData(FALSE);
}
}
(2)加载文件、目录信息
void CFTPClientDlg::LoadFileList()
{
m_listbox_files.ResetContent();
CFtpFileFind fileFind(m_ftpConnection);
CString fileName;
BOOL bMoreFiles=fileFind.FindFile();
while(bMoreFiles)
{
bMoreFiles=fileFind.FindNextFile();
fileName=fileFind.GetFileName();
if(fileFind.IsDirectory()){
fileName+=" <dir>";
}
m_listbox_files.AddString(fileName);
}
fileFind.Close();
}
(3)下载文件
void CFTPClientDlg::OnButtonDownload()
{
// TODO: Add your control notification handler code here
UpdateData(TRUE);
if(m_str_filename!=""){
if(m_str_filename.Right(5)=="<dir>"){
MessageBox("不能下载目录");
}
else{
CFileDialog saveDialog(FALSE,NULL,m_str_filename);
if(saveDialog.DoModal()==IDOK)
{
if(!m_ftpConnection->GetFile(m_str_filename,saveDialog.GetFileName()),FALSE)
MessageBox("文件下载失败!");
else
MessageBox("成功下载 "+m_str_filename);
}
}
}
}
五. 实验结果
服务器运行效果如下:
主界面,运行状态显示
账号列表,编辑用户信息
在线用户列表
客户端运行效果如下:
不足的是,本次设计的FTP客户端程序较简单,只是为了简单验证服务器的可用性,所以只实现了文件的下载功能,后期将会尝试加上文件上传、删除以及目录创建等功能。
win32FTP程序设计的更多相关文章
- HTML5 程序设计 - 使用HTML5 Canvas API
请你跟着本篇示例代码实现每个示例,30分钟后,你会高喊:“HTML5 Canvas?!在哥面前,那都不是事儿!” 呵呵.不要被滚动条吓到,很多都是代码和图片.我没有分开写,不过上面给大家提供了目录,方 ...
- 解析大型.NET ERP系统 单据标准(新增,修改,删除,复制,打印)功能程序设计
ERP系统的单据具备标准的功能,这里的单据可翻译为Bill,Document,Entry,具备相似的工具条操作界面.通过设计可复用的基类,子类只需要继承基类窗体即可完成单据功能的程序设计.先看标准的销 ...
- java基础学习03(java基础程序设计)
java基础程序设计 一.完成的目标 1. 掌握java中的数据类型划分 2. 8种基本数据类型的使用及数据类型转换 3. 位运算.运算符.表达式 4. 判断.循环语句的使用 5. break和con ...
- CWMP开源代码研究5——CWMP程序设计思想
声明:本文涉及的开源程序代码学习和研究,严禁用于商业目的. 如有任何问题,欢迎和我交流.(企鹅号:408797506) 本文介绍自己用过的ACS,其中包括开源版(提供下载包)和商业版(仅提供安装包下载 ...
- 《JavaScript高级程序设计(第3版)》笔记-序
很少看书,不喜欢看书,主要是上学时总坐不住,没有多大定性,一本书可以两天看完,随便翻翻,也可以丢在角落里几个月不去动一下. 上次碰到了<JavaScript高级程序设计(第3版)>感觉真的 ...
- 《JavaScript高级程序设计(第3版)》阅读总结记录第一章之JavaScript简介
前言: 为什么会想到把<JavaScript 高级程序设计(第 3 版)>总结记录呢,之前写过一篇博客,研究的轮播效果,后来又去看了<JavaScript 高级程序设计(第3版)&g ...
- 【实战Java高并发程序设计 7】让线程之间互相帮助--SynchronousQueue的实现
[实战Java高并发程序设计 1]Java中的指针:Unsafe类 [实战Java高并发程序设计 2]无锁的对象引用:AtomicReference [实战Java高并发程序设计 3]带有时间戳的对象 ...
- 【实战Java高并发程序设计6】挑战无锁算法:无锁的Vector实现
[实战Java高并发程序设计 1]Java中的指针:Unsafe类 [实战Java高并发程序设计 2]无锁的对象引用:AtomicReference [实战Java高并发程序设计 3]带有时间戳的对象 ...
- 【实战Java高并发程序设计 5】让普通变量也享受原子操作
[实战Java高并发程序设计 1]Java中的指针:Unsafe类 [实战Java高并发程序设计 2]无锁的对象引用:AtomicReference [实战Java高并发程序设计 3]带有时间戳的对象 ...
随机推荐
- iOS method swizz
1: 防止按钮在一定时间内重复响应默认1秒 // // UIButton+AvoidDoubleClick.h // 51WaywardShop // // Created by jisa on 20 ...
- 哈夫曼树——c++
哈夫曼树的介绍 Huffman Tree,中文名是哈夫曼树或霍夫曼树,它是最优二叉树. 定义:给定n个权值作为n个叶子结点,构造一棵二叉树,若树的带权路径长度达到最小,则这棵树被称为哈夫曼树. 这个定 ...
- CentOS7下 Python2.7.5升级为Python2.7.13
参考:https://www.jianshu.com/p/fad3942fc0ed 第一步:查看Centos版本及Python版本 • CentOS版本 [root@ tools_package]# ...
- 刚才在windows下发现拖拽不了文件了
百度了下 摁了两下esc就可以了.以下是百度得到的答案 按几下Esc目的是:没按前ESC键[接触不好]或[键不灵]或其他原因导致ESC处于[按下]状态,这样鼠标就会拖不了文件,点击菜单也会马上消失, ...
- 克隆linux虚拟机
背景:有时候,我们在用虚拟机的时候会用到多个进行使用.重新安装会花费大量的时间,此时,我们可以通过vmware虚拟机自带的功能快速克隆出完全相同的系统. 前提:被克隆的虚拟机系统要处于关闭状态 步骤: ...
- C#里面const和readonly
一.const关键字限定一个变量不允许被改变. 使用const在一定程度上可以提高程序的安全性和可靠性. 1.用于修改字段或局部变量的声明,表示指定的字段或局部变量的值是常数,不能被修改. 2.常数声 ...
- css四种选择器总结
css 在网页开发中扮演着重要的角色,被誉为网页开发的三剑客,如果说html是人的外在器官部分,那css无疑是各个器官组成在一起然后表现出来,css又称样式重叠在网页排版布局中的地位举足轻重. 做 ...
- 【2018北京集训6】Lcm DFT&FWT
首先我们来看下此题的模数232792561. 232792561=lcm(1,2,3.......20)+1.这个性质将在求值时用到. 我们将n分解质因数,令$m$为$n$的素因子个数,设n=$\Pi ...
- mysql ERROR 1045 (28000): Access denied for user 可能解决方法分析
在实际登录redmine的过程中,我们遇到了如下的error ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using ...
- 第5章—构建Spring Web应用程序—关于spring中的validate注解后台校验的解析
关于spring中的validate注解后台校验的解析 在后台开发过程中,对参数的校验成为开发环境不可缺少的一个环节.比如参数不能为null,email那么必须符合email的格式,如果手动进行if判 ...