掌握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. C++一些函数的意义

    1.重载 : C++ 允许多个函数拥有相同的名字,只要它们的参数列表不同就可以,这就是函数的重载 2.隐藏和覆盖的区别 IF 子类的函数与父类的名称相同,但是参数不同 父类函数被隐藏(还存在) ELS ...

  2. JQuery Mobile - 为什么绑定事件后会被多次执行?

    JQuery Mobile 在绑定事件时候,发现会被多次执行,为什么啊? 原来,jquery click  不是替换原有的function ,而是接着添加,所以才会执行次数越来越多,怎么办才能按需实现 ...

  3. 768. Max Chunks To Make Sorted II

    This question is the same as "Max Chunks to Make Sorted" except the integers of the given ...

  4. tomcat JNDI Resource 配置

    最近公司的项目慢慢开始向Maven项目迁移, 部分配置文件公共组也帮我们做了些改动,其中在spring的applicationContext.xml中看到了数据连接bean存在两个,一个是jndi 一 ...

  5. docker安装指定版本TAG的镜像

    在docker中安装镜像,一般过程是,docker search 软件名称. 本文以tomcat为例,讲解下载指定版本TAG的tomcat. 搜索tomcat镜像 $ sudo docker sear ...

  6. C#获取文件版本、文件大小等信息

    使用以下C#程序代码可以非常方便地获取Windows系统中任意一个文件(尤其是可执行文件)的文件版本.文件大小.版权.产品名称等信息.所获取到的信息类似于在Windows操作系统中右键点击该文件,然后 ...

  7. Docker学习--Linux基础准备篇

    1.docker命令不需要附带敲sudo的解决办法 由于docker daemon需要绑定到主机的Unix socket而不是普通的TCP端口,而Unix socket的属主为root用户,所以其他用 ...

  8. diskpart 格式化u盘 制作u盘启动盘方法

    1.cmd 2.diskpart 3.list disk 4.select disk [index]   注:[index] 磁盘索引号 5.clean 6.create partition prim ...

  9. BugFree3.0.4Linux环境安装指南

    bugfree安装的前提是配置LAMP(apache+mysql+php),我安装的linux系统是centos6.0 一.安装Apache服务器 1.安装apache yum install htt ...

  10. springboot-mongodb的多数据源配置

    pom.xml中引入mongodb的依赖 <dependency> <groupId>org.springframework.boot</groupId> < ...