zoukankan      html  css  js  c++  java
  • win32FTP程序设计

    掌握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客户端程序较简单,只是为了简单验证服务器的可用性,所以只实现了文件的下载功能,后期将会尝试加上文件上传、删除以及目录创建等功能。

  • 相关阅读:
    判断两个链表是否相交
    【转】TCP连接突然断开的处理方法
    【转】TCP/IP协议——ARP详解
    HTTP协议COOKIE和SESSION有什么区别
    【转】K-Means聚类算法原理及实现
    【转】机器学习实战之K-Means算法
    unity3d 调用Start 注意
    u3d 加载PNG做 UI图片
    Opengl的gl_NormalMatrix
    OpenGL 遮挡查询
  • 原文地址:https://www.cnblogs.com/leftshine/p/5698743.html
Copyright © 2011-2022 走看看