码迷,mamicode.com
首页 > Windows程序 > 详细

win32FTP程序设计

时间:2016-07-23 16:29:57      阅读:326      评论:0      收藏:0      [点我收藏+]

标签:

掌握socket基于事件机制的网络程序设计,掌握多线程技术的FTP Server端设计方法,掌握FTP标准基本协议及其程序的实现,掌握文件内容的网络传输设计方法。

利用CFtpServer类接收和解析客户端命令,编写FTP客户端程序,服务器端使用多线程,实现多用户同时登录管理;

利用CFtpConnection和CInternetSession类,编写FTP客户端,实现简单文件操作功能。

  1. 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();

    }

    ?

  2. 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程序设计

标签:

原文地址:http://www.cnblogs.com/leftshine/p/5698743.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!