当前位置:文档之家› FTP服务器与客户端设计与开发

FTP服务器与客户端设计与开发

FTP服务器与客户端设计与开发详细设计程序包括5个主要功能:1.服务器的运行:启动和停止FTP服务2.用户管理:添加用户,删除用户和设置用户权限3.服务器配置:设置服务器开放端口,最大连接数等4.运行统计:统计当前服务器运行时期上传下载的流量等等5.安全设置:允许连接服务器的IP列表,以及禁止访问的IP服务器的运行模块功能:负责FTP服务器的运行。

使用类:CFTPServer类,CApplicationDlg类,CListenSocket类,CConnectThread类,CConnectSocket类各种类的功能:1.CFTPServer类:是CWnd的子类,作为程序的顶层类,负责实现或者调用各个成员函数2.CApplicationDlg类:CDialog类的子类,实现程序主窗口。

3.CListenSocket类:负责监听FTP客户端连接,并实现有效连接onnectThread类:负责实现并保证多个连接的有效性。

onnectSocket类:实现FTP命令的解析,数据的发送和接收CFTPServer类作为服务器的顶层类,实现服务器开始运行时的所有成员函数申明如下:class CFTPServer : public CWnd{friend CConnectSocket;//CConnectSocket作为其友元类,可以访问内部私有数据成员public:void SetGoodbyeMessage(LPCTSTR lpszText);//发送退出信息void SetWelcomeMessage(LPCTSTR lpszText);//发送欢迎信息void SetTimeout(int nValue);//设置暂停时间void SetPort(int nValue);//设置端口void SetMaxUsers(int nValue);//设置最大连接数void SetStatisticsInterval(int nValue);//统计时间间隔BOOL IsActive();//是否有效void Stop();BOOL Start();CFTPServer();virtual ~CFTPServer();CUserManager m_UserManager;//用户管理对象CSecurityManager m_SecurityManager;//安全策略CFTPServer类最主要的成员函数是start()和stop(),分别负责ftp服务器的开始运行和结束运行函数声明如下:/********************************************************************//* *//* Function name : Start *//* Description : Start listining on port 21 and accept new *//* connections. *//* *//********************************************************************/BOOL CFTPServer::Start(){if (m_bRunning)return FALSE;//如果运行,返回错误标志// create dummy window for message routingif (!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;}// 开始创建socketif (m_ListenSocket.Create(m_nPort)){// start listeningif (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 windowif (IsWindow(m_hWnd))DestroyWindow();m_hWnd = NULL;return FALSE;}/********************************************************************/ /* */ /* Function name : Stop */ /* Description : Stop FTP server. */ /* */ /********************************************************************/ void CFTPServer::Stop(){if (!m_bRunning)return;// stop statistics timerKillTimer(1);m_bRunning = FALSE;m_ListenSocket.Close();CConnectThread* pThread = NULL;// close all running threadsdo{m_CriticalSection.Lock();POSITION pos = m_ThreadList.GetHeadPosition();if (pos != NULL){pThread = (CConnectThread *)m_ThreadList.GetAt(pos);m_CriticalSection.Unlock();// save thread membersint nThreadID = pThread->m_nThreadID;HANDLE hThread = pThread->m_hThread;AddTraceLine(0, "[%d] Shutting down thread...", nThreadID);// tell thread to stoppThread->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 stoppedAddTraceLine(0, "[%d] Problem while killing thread.", nThreadID);// don't try again, so removem_CriticalSection.Lock();POSITION rmPos = m_ThreadList.Find(pThread);if (rmPos != NULL)m_ThreadList.RemoveAt(rmPos);m_CriticalSection.Unlock();}else{AddTraceLine(0, "[%d] 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;}CListenSocket类用于监听每个客户的连接,CListenSocket类是CAsyncSocket的子类,其成员函数listen 监听来自客户端的连接,当监听到可以接收的socket的时候通过OnAccept函数准备创建有效连接的进程。

函数如下:void CListenSocket::OnAccept(int nErrorCode){// New connection is being establishedCSocket sockit;// Accept the connection using a temp CSocket object.Accept(sockit);// Create a thread to handle the connection. The thread is created suspended so that we can// set variables in CConnectThread before it starts executing.CConnectThread* pThread =(CConnectThread*)AfxBeginThread(RUNTIME_CLASS(CConnectThread),THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);if (!pThread){sockit.Close();TRACE("Could not create thread\n");return;}CFTPServer *pWnd = (CFTPServer *)m_pWndServer;// since everything is successful, add the thread to our list pWnd->m_CriticalSection.Lock();pWnd->m_ThreadList.AddTail(pThread);pWnd->m_CriticalSection.Unlock();// save pointerpThread->m_pWndServer = m_pWndServer;// Pass the socket to the thread by passing the socket handle. You cannot pass // a CSocket object across threads.pThread->m_hSocket = sockit.Detach();// Now start the thread.pThread->ResumeThread();}CConnectThread类CConnectThread类负责为每个有效进程创建一个线程,每个进程完成数据传输的所有任务,穿件县城后通过InitInstance完成线程的初始化BOOL CConnectThread::InitInstance(){try{// Attach the socket handle to a CSocket object.// This makes sure that the socket notifications are sent to this thread.m_ConnectSocket.Attach(m_hSocket);m_ConnectSocket.m_pThread = this;CString strIPAddress;UINT nPort;m_ConnectSocket.GetPeerName(strIPAddress, nPort);// notify server that there's a new connectionm_pWndServer->SendMessage(WM_THREADSTART, (WPARAM)this, 0);if (((CFTPServer *)m_pWndServer)->CheckMaxUsers()){m_ConnectSocket.SendResponse("421 Too many users are connected, please try again later.");PostThreadMessage(WM_QUIT,0,0);}elseif (!((CFTPServer *)m_pWndServer)->IsIPAddressAllowed(strIPAddress)){m_ConnectSocket.SendResponse("421 Access denied, IP address was rejected by the server.");PostThreadMessage(WM_QUIT,0,0);}else{// send welcome message to clientCString strText = ((CFTPServer *)m_pWndServer)->GetWelcomeMessage();m_ConnectSocket.SendResponse("220 " + strText);m_nTimerID = ::SetTimer(NULL, 0, 1000, TimerProc);}}catch(CException *e){e->Delete();}return TRUE;}线程结束以后,通过ExitInstance函数实现资源的释放代码如下:int CConnectThread::ExitInstance(){CFTPServer *pWnd = (CFTPServer *)m_pWndServer;try{pWnd->m_CriticalSection.Lock();// delete this thread from the linked listPOSITION pos = pWnd->m_ThreadList.Find(this);if(pos != NULL){pWnd->m_ThreadList.RemoveAt(pos);}pWnd->m_CriticalSection.Unlock();// notify service main looppWnd->SendMessage(WM_THREADCLOSE, (WPARAM)this, 0);}catch(CException *e){pWnd->m_CriticalSection.Unlock();e->Delete();}return CWinThread::ExitInstance();}为了了解传输过程中接收和发送的字节数,使用IncReceivedBytes和IncSentBytes来计算。

相关主题