收藏 分销(赏)

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

上传人:精**** 文档编号:3068496 上传时间:2024-06-14 格式:DOC 页数:32 大小:99.50KB
下载 相关 举报
FTP服务器与客户端设计与开发.doc_第1页
第1页 / 共32页
FTP服务器与客户端设计与开发.doc_第2页
第2页 / 共32页
FTP服务器与客户端设计与开发.doc_第3页
第3页 / 共32页
FTP服务器与客户端设计与开发.doc_第4页
第4页 / 共32页
FTP服务器与客户端设计与开发.doc_第5页
第5页 / 共32页
点击查看更多>>
资源描述

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

2、负责实现或者调用各个成员函数2. CApplicationDlg类:CDialog类的子类,实现程序主窗口。3. CListenSocket类:负责监听FTP客户端连接,并实现有效连接4. CConnectThread类:负责实现并保证多个连接的有效性。5. CConnectSocket类:实现FTP命令的解析,数据的发送和接收CFTPServer类作为服务器的顶层类,实现服务器开始运行时的所有成员函数申明如下:class CFTPServer : public CWndfriend CConnectSocket;/CConnectSocket作为其友元类,可以访问内部私有数据成员public

3、: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();CFTPServe

4、r();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_b

5、Running)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;/ 开始创建socketif (m_ListenSocket.Create(m_nPort)/ start

6、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 (Is

7、Window(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 th

8、readsdom_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 th

9、read., 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 doesnt want to stoppedAddTraceLine(0, %

10、d Problem while killing thread., nThreadID);/ dont try again, so removem_CriticalSection.Lock();POSITION rmPos = m_ThreadList.Find(pThread);if (rmPos != NULL)m_ThreadList.RemoveAt(rmPos);m_CriticalSection.Unlock();elseAddTraceLine(0, %d Thread successfully stopped., nThreadID);elsem_CriticalSection.

11、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 nErrorC

12、ode) / 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 =

13、 (CConnectThread*)AfxBeginThread(RUNTIME_CLASS(CConnectThread), THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);if (!pThread)sockit.Close();TRACE(Could not create threadn);return;CFTPServer *pWnd = (CFTPServer *)m_pWndServer; / since everything is successful, add the thread to our listpWnd-m_CriticalSe

14、ction.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

15、.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_hSocke

16、t);m_ConnectSocket.m_pThread = this;CString strIPAddress;UINT nPort;m_ConnectSocket.GetPeerName(strIPAddress, nPort);/ notify server that theres a new connectionm_pWndServer-SendMessage(WM_THREADSTART, (WPARAM)this, 0);if (CFTPServer *)m_pWndServer)-CheckMaxUsers()m_ConnectSocket.SendResponse(421 To

17、o 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 t

18、o 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 = (

19、CFTPServer *)m_pWndServer;trypWnd-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);

20、catch(CException *e) pWnd-m_CriticalSection.Unlock();e-Delete();return CWinThread:ExitInstance();为了了解传输过程中接收和发送的字节数,使用IncReceivedBytes和IncSentBytes来计算。这两个函数在CConnectSocket类中调用,代码如下:void CConnectThread:IncSentBytes(int nBytes)m_LastDataTransferTime = CTime:GetCurrentTime();m_nSentBytes += nBytes;/ no

21、tify server classm_pWndServer-PostMessage(WM_THREADMSG, (WPARAM)0, (LPARAM)nBytes);void CConnectThread:IncReceivedBytes(int nBytes)m_LastDataTransferTime = CTime:GetCurrentTime();m_nReceivedBytes += nBytes;/ notify server classm_pWndServer-PostMessage(WM_THREADMSG, (WPARAM)1, (LPARAM)nBytes);CConnec

22、tSocket类每个线程都是通过一个CConnectSocket对象m_ConnectSocket来完成数据的接受和发送。当线程创建成功以后,m_ConnectSocket对象通过OnReceive函数获得数据,然后利用ParseCommand函数来解析其中FTP命令void CConnectSocket:OnReceive(int nErrorCode) TCHAR buffBUFFERSIZE;int nRead = Receive(buff, BUFFERSIZE);switch (nRead)case 0:Close();break;case SOCKET_ERROR:if (GetL

23、astError() != WSAEWOULDBLOCK) TCHAR szError256;wsprintf(szError, OnReceive error: %d, GetLastError();AfxMessageBox (szError);break;default:if (nRead != SOCKET_ERROR & nRead != 0)(CConnectThread *)AfxGetThread()-IncReceivedBytes(nRead);/ terminate the stringbuffnRead = 0; m_RxBuffer += CString(buff);

24、GetRxLine();break;CSocket:OnReceive(nErrorCode);ParseCommand函数是当前程序最重要的一个部分,它根据客户端提交的各种命令进行相应的操作代码如下void CConnectSocket:ParseCommand()static CFTPCommand commandList = TOK_USER,USER, TRUE,TOK_PASS,PASS, TRUE,TOK_CWD,CWD,TRUE,TOK_PWD,PWD,FALSE,TOK_PORT,PORT, TRUE,TOK_PASV,PASV, FALSE,TOK_TYPE,TYPE, TR

25、UE,TOK_LIST,LIST, FALSE,TOK_REST,REST, TRUE,TOK_CDUP,CDUP, FALSE,TOK_RETR,RETR, TRUE,TOK_STOR,STOR, TRUE,TOK_SIZE,SIZE, TRUE,TOK_DELE,DELE, TRUE,TOK_RMD,RMD,TRUE,TOK_MKD,MKD,TRUE,TOK_RNFR,RNFR, TRUE,TOK_RNTO,RNTO, TRUE,TOK_ABOR,ABOR, FALSE, TOK_SYST,SYST, FALSE,TOK_NOOP,NOOP, FALSE,TOK_BYE,BYE, FALS

26、E,TOK_QUIT,QUIT, FALSE,TOK_ERROR,FALSE,;/ parse commandCString strCommand, strArguments;if (!GetRxCommand(strCommand, strArguments)return;int nCommand;/查找命令for (nCommand = TOK_USER; nCommand TOK_PASS & !m_bLoggedon)SendResponse(530 Please log in with USER and PASS first.);return;/ proces commandswit

27、ch(nCommand)/ specify usernamecase TOK_USER:strArguments.MakeLower();m_bLoggedon = FALSE;m_strUserName = strArguments;CString strPeerAddress;UINT nPeerPort;GetPeerName(strPeerAddress, nPeerPort);/ tell FTP server a new user has connectedCConnectThread *pThread = (CConnectThread *)m_pThread;(CFTPServ

28、er *)pThread-m_pWndServer)-m_pEventSink-OnFTPUserConnected(m_pThread-m_nThreadID, m_strUserName, strPeerAddress);SendResponse(331 Password required for + strArguments);break;/ specify passwordcase TOK_PASS:/ already logged on ?if (m_bLoggedon)SendResponse(503 Bad sequence of commands.);else/ check u

29、ser and passwordCUser user;if (theServer.m_UserManager.CheckUser(m_strUserName, strArguments, user)/设置用户主目录m_strCurrentDir = /;/ 成功登录提示m_bLoggedon = TRUE;SendResponse(230 Logged on);else SendResponse(530 Login or password incorrect!);break;/ change current directorycase TOK_CWD:int nResult = theServ

30、er.m_UserManager.ChangeDirectory(m_strUserName, m_strCurrentDir, strArguments);CString str;switch(nResult)case 0:str.Format(250 CWD successful. %s is current directory., m_strCurrentDir);SendResponse(str);break;case 1:str.Format(550 CWD failed. %s: Permission denied., strArguments);SendResponse(str)

31、;break;default:str.Format(550 CWD failed. %s: directory not found., strArguments);SendResponse(str);break;break; / print current directorycase TOK_PWD:CString str;str.Format(257 %s is current directory., m_strCurrentDir);SendResponse(str);break;/ specify IP and port (PORT a1,a2,a3,a4,p1,p2) - IP add

32、ress a1.a2.a3.a4, port p1*256+p2. case TOK_PORT:CString strSub;int nCount=0;while (AfxExtractSubString(strSub, strArguments, nCount+, ,)switch(nCount)case 1:/ a1m_TransferStatus.m_strRemoteHost = strSub;m_TransferStatus.m_strRemoteHost += .;break;case 2:/ a2m_TransferStatus.m_strRemoteHost += strSub

33、;m_TransferStatus.m_strRemoteHost += .;break;case 3:/ a3m_TransferStatus.m_strRemoteHost += strSub;m_TransferStatus.m_strRemoteHost += .;break;case 4:/ a4m_TransferStatus.m_strRemoteHost += strSub;break;case 5:/ p1m_TransferStatus.m_nRemotePort = 256*atoi(strSub);break;case 6:/ p2m_TransferStatus.m_

34、nRemotePort += atoi(strSub);break;m_TransferStatus.m_bPassiveMode = FALSE;SendResponse(200 Port command successful);break;/ switch to passive modecase TOK_PASV:/ delete existing datasocketDestroyDataSocket();/ create new data socketm_TransferStatus.m_pDataSocket = new CDataSocket(this, -1);if (!m_Tr

35、ansferStatus.m_pDataSocket-Create()DestroyDataSocket();SendResponse(421 Cant create socket);break;/ start listeningm_TransferStatus.m_pDataSocket-Listen();m_TransferStatus.m_pDataSocket-AsyncSelect();CString strIP, strTmp;UINT nPort;/ get our ip addressGetSockName(strIP, nPort);/ Now retrieve the po

36、rtm_TransferStatus.m_pDataSocket-GetSockName(strTmp, nPort);/ Reformat the ipstrIP.Replace(.,);/ tell the client which address/port to connect toCString str;str.Format(227 Entering Passive Mode (%s,%d,%d), strIP, nPort/256, nPort%256);SendResponse(str);m_TransferStatus.m_bPassiveMode = TRUE;break; c

37、ase TOK_TYPE:SendResponse(200 Type set to + strArguments);break;/ list current directorycase TOK_LIST:if(!m_TransferStatus.m_bPassiveMode & (m_TransferStatus.m_strRemoteHost = | m_TransferStatus.m_nRemotePort = -1)SendResponse(503 Bad sequence of commands.);else/ if client did not specify a directory use current dirif (strArguments = )strArguments = m_strCurrentDir;else/ check if argument is file or directoryCString strResult;int nResult = theServer.m_UserManager.GetFileName(m_strUserName, strArguments, m_strCurrentDir, FTP_LIST, strResult);if (nRes

展开阅读全文
相似文档                                   自信AI助手自信AI助手
猜你喜欢                                   自信AI导航自信AI导航
搜索标签

当前位置:首页 > 包罗万象 > 大杂烩

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        获赠5币

©2010-2024 宁波自信网络信息技术有限公司  版权所有

客服电话:4008-655-100  投诉/维权电话:4009-655-100

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :gzh.png    weibo.png    LOFTER.png 

客服