您的位置:首页 > 编程语言 > PHP开发

win32FTP程序设计

2016-07-23 15:09 405 查看
掌握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客户端程序较简单,只是为了简单验证服务器的可用性,所以只实现了文件的下载功能,后期将会尝试加上文件上传、删除以及目录创建等功能。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: