掌握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程序设计的更多相关文章

  1. HTML5 程序设计 - 使用HTML5 Canvas API

    请你跟着本篇示例代码实现每个示例,30分钟后,你会高喊:“HTML5 Canvas?!在哥面前,那都不是事儿!” 呵呵.不要被滚动条吓到,很多都是代码和图片.我没有分开写,不过上面给大家提供了目录,方 ...

  2. 解析大型.NET ERP系统 单据标准(新增,修改,删除,复制,打印)功能程序设计

    ERP系统的单据具备标准的功能,这里的单据可翻译为Bill,Document,Entry,具备相似的工具条操作界面.通过设计可复用的基类,子类只需要继承基类窗体即可完成单据功能的程序设计.先看标准的销 ...

  3. java基础学习03(java基础程序设计)

    java基础程序设计 一.完成的目标 1. 掌握java中的数据类型划分 2. 8种基本数据类型的使用及数据类型转换 3. 位运算.运算符.表达式 4. 判断.循环语句的使用 5. break和con ...

  4. CWMP开源代码研究5——CWMP程序设计思想

    声明:本文涉及的开源程序代码学习和研究,严禁用于商业目的. 如有任何问题,欢迎和我交流.(企鹅号:408797506) 本文介绍自己用过的ACS,其中包括开源版(提供下载包)和商业版(仅提供安装包下载 ...

  5. 《JavaScript高级程序设计(第3版)》笔记-序

    很少看书,不喜欢看书,主要是上学时总坐不住,没有多大定性,一本书可以两天看完,随便翻翻,也可以丢在角落里几个月不去动一下. 上次碰到了<JavaScript高级程序设计(第3版)>感觉真的 ...

  6. 《JavaScript高级程序设计(第3版)》阅读总结记录第一章之JavaScript简介

    前言: 为什么会想到把<JavaScript 高级程序设计(第 3 版)>总结记录呢,之前写过一篇博客,研究的轮播效果,后来又去看了<JavaScript 高级程序设计(第3版)&g ...

  7. 【实战Java高并发程序设计 7】让线程之间互相帮助--SynchronousQueue的实现

    [实战Java高并发程序设计 1]Java中的指针:Unsafe类 [实战Java高并发程序设计 2]无锁的对象引用:AtomicReference [实战Java高并发程序设计 3]带有时间戳的对象 ...

  8. 【实战Java高并发程序设计6】挑战无锁算法:无锁的Vector实现

    [实战Java高并发程序设计 1]Java中的指针:Unsafe类 [实战Java高并发程序设计 2]无锁的对象引用:AtomicReference [实战Java高并发程序设计 3]带有时间戳的对象 ...

  9. 【实战Java高并发程序设计 5】让普通变量也享受原子操作

    [实战Java高并发程序设计 1]Java中的指针:Unsafe类 [实战Java高并发程序设计 2]无锁的对象引用:AtomicReference [实战Java高并发程序设计 3]带有时间戳的对象 ...

随机推荐

  1. CEPH 创建 RPM 安装包

    1.安装依赖环境 yum install gcc make python-devel openssl-devel graphviz autoconf automake rpm-build redhat ...

  2. Python(网络基础)

    day33 参考:http://www.cnblogs.com/linhaifeng/articles/5937962.html IP协议: 规定网络地址的协议叫ip协议,它定义的地址称之为ip地址, ...

  3. 内核漏洞学习—熟悉HEVD

    一直以来内核漏洞安全给很多人的印象就是:难,枯燥.但是内核安全是否掌握是衡量一个系统安全工程师水平的标准之一,也是安全从业人员都应该掌握的基本功.本文通过详细的实例带领读者走进内核安全的大门.难度系数 ...

  4. 初识storm

    storm是Twitter开发的一个开源的分布式实时计算系统,可以简单可靠的处理大量的数据流.storm有很多的应用场景,如实时分析,在线机器学习,持续计算,分布式RPC,ETL等等.storm支持水 ...

  5. mysql编写存储过程(2)

    书接上回. 实例8:if-then -else语句 实例9:case语句: 实例10:循环语句,while ···· end while: 实例11:循环语句,repeat···· end repea ...

  6. OS之进程管理 --- 死锁

    什么是死锁 在正常操作模式下,进程按如下顺序来使用资源: 申请:进程请求资源 使用:进程对资源进行操作 释放:进程释放资源 当一组进程中的每一个进程度在等待一个事件,而这事件只能有一组进程的另一个进程 ...

  7. spring基础回顾

    1.什么是Spring框架?Spring框架有哪些主要模块? Spring框架是一个为Java应用程序的开发提供了综合.广泛的基础性支持的Java平台.Spring帮助开发者解决了开发中基础性的问题, ...

  8. easyui datagrid 清除缓存方法

    easyui datagrid 清除缓存方法 今天在项目中做了一个添加合同编号页面,添加合同编号了,在datagrid列表上没有显示刚才添加的那个合同编号. 这个问题在IE上特别明显. 原因是添加编号 ...

  9. (转)MYSQL线程池总结(一)

    MYSQL线程池总结(一)  原文:http://www.cnblogs.com/cchust/p/4510039.html 线程池是Mysql5.6的一个核心功能,对于服务器应用而言,无论是web应 ...

  10. Dubbo架构设计详解(转载)

    原文地址:http://shiyanjun.cn/archives/325.html Dubbo是Alibaba开源的分布式服务框架,它最大的特点是按照分层的方式来架构,使用这种方式可以使各个层之间解 ...