FTP服务器与客户端设计与开发Word文件下载.doc
《FTP服务器与客户端设计与开发Word文件下载.doc》由会员分享,可在线阅读,更多相关《FTP服务器与客户端设计与开发Word文件下载.doc(32页珍藏版)》请在冰点文库上搜索。
![FTP服务器与客户端设计与开发Word文件下载.doc](https://file1.bingdoc.com/fileroot1/2023-4/30/b03b954d-1bf0-4c9e-b66c-59a9c413e022/b03b954d-1bf0-4c9e-b66c-59a9c413e0221.gif)
public:
voidSetGoodbyeMessage(LPCTSTRlpszText);
//发送退出信息
voidSetWelcomeMessage(LPCTSTRlpszText);
//发送欢迎信息
voidSetTimeout(intnValue);
//设置暂停时间
voidSetPort(intnValue);
//设置端口
voidSetMaxUsers(intnValue);
//设置最大连接数
voidSetStatisticsInterval(intnValue);
//统计时间间隔
BOOLIsActive();
//是否有效
voidStop();
BOOLStart();
CFTPServer();
virtual~CFTPServer();
CUserManagerm_UserManager;
//用户管理对象
CSecurityManagerm_SecurityManager;
//安全策略
最主要的成员函数是start()和stop(),分别负责ftp服务器的开始运行和结束运行
函数声明如下:
/********************************************************************/
/* */
/*Functionname:
Start */
/*Description:
Startlistiningonport21andacceptnew */
/* connections. */
BOOLCFTPServer:
:
Start()
if(m_bRunning)
returnFALSE;
//如果运行,返回错误标志
//createdummywindowformessagerouting
if(!
CWnd:
CreateEx(0,AfxRegisterWndClass(0),"
FTPServerNotificationSink"
WS_POPUP,0,0,0,0,NULL,0))
{
AddTraceLine(0,"
Failedtocreatenotificationwindow."
);
}
//开始创建socket
if(m_ListenSocket.Create(m_nPort))
//startlistening
if(m_ListenSocket.Listen())
{
m_ListenSocket.m_pWndServer=this;
m_bRunning=TRUE;
SetTimer(1,m_nStatisticsInterval,NULL);
AddTraceLine(0,"
FTPServerstartedonport%d."
m_nPort);
returnTRUE;
}
AddTraceLine(0,"
FTPServerfailedtolistenonport%d."
//destroynotificationwindow
if(IsWindow(m_hWnd))
DestroyWindow();
m_hWnd=NULL;
returnFALSE;
}
Stop */
StopFTPserver. */
voidCFTPServer:
Stop()
if(!
m_bRunning)
return;
//stopstatisticstimer
KillTimer
(1);
m_bRunning=FALSE;
m_ListenSocket.Close();
CConnectThread*pThread=NULL;
//closeallrunningthreads
do
m_CriticalSection.Lock();
POSITIONpos=m_ThreadList.GetHeadPosition();
if(pos!
=NULL)
pThread=(CConnectThread*)m_ThreadList.GetAt(pos);
m_CriticalSection.Unlock();
//savethreadmembers
intnThreadID=pThread->
m_nThreadID;
HANDLEhThread=pThread->
m_hThread;
[%d]Shuttingdownthread..."
nThreadID);
//tellthreadtostop
pThread->
SetThreadPriority(THREAD_PRIORITY_HIGHEST);
PostThreadMessage(WM_QUIT,0,0);
//waitforthreadtoend,whilekeepingthemessagespumping(max5seconds)
if(WaitWithMessageLoop(hThread,5000)==FALSE)
{
//threaddoesn'
twanttostopped
AddTraceLine(0,"
[%d]Problemwhilekillingthread."
//don'
ttryagain,soremove
m_CriticalSection.Lock();
POSITIONrmPos=m_ThreadList.Find(pThread);
if(rmPos!
m_ThreadList.RemoveAt(rmPos);
m_CriticalSection.Unlock();
}
else
[%d]Threadsuccessfullystopped."
else
pThread=NULL;
while(pThread!
=NULL);
FTPServerstopped."
CListenSocket类
用于监听每个客户的连接,CListenSocket类是CAsyncSocket的子类,其成员函数listen监听来自客户端的连接,当监听到可以接收的socket的时候通过OnAccept函数准备创建有效连接的进程。
函数如下:
voidCListenSocket:
OnAccept(intnErrorCode)
//Newconnectionisbeingestablished
CSocketsockit;
//AccepttheconnectionusingatempCSocketobject.
Accept(sockit);
//Createathreadtohandletheconnection.Thethreadiscreatedsuspendedsothatwecan
//setvariablesinCConnectThreadbeforeitstartsexecuting.
CConnectThread*pThread=(CConnectThread*)AfxBeginThread(RUNTIME_CLASS(CConnectThread),THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);
pThread)
sockit.Close();
TRACE("
Couldnotcreatethread\n"
CFTPServer*pWnd=(CFTPServer*)m_pWndServer;
//sinceeverythingissuccessful,addthethreadtoourlist
pWnd->
m_CriticalSection.Lock();
pWnd->
m_ThreadList.AddTail(pThread);
m_CriticalSection.Unlock();
//savepointer
pThread->
m_pWndServer=m_pWndServer;
//Passthesockettothethreadbypassingthesockethandle.Youcannotpass
//aCSocketobjectacrossthreads.
m_hSocket=sockit.Detach();
//Nowstartthethread.
ResumeThread();
}
CConnectThread类
CConnectThread类负责为每个有效进程创建一个线程,每个进程完成数据传输的所有任务,穿件县城后通过InitInstance完成线程的初始化
BOOLCConnectThread:
InitInstance()
try
//AttachthesockethandletoaCSocketobject.
//Thismakessurethatthesocketnotificationsaresenttothisthread.
m_ConnectSocket.Attach(m_hSocket);
m_ConnectSocket.m_pThread=this;
CStringstrIPAddress;
UINTnPort;
m_ConnectSocket.GetPeerName(strIPAddress,nPort);
//notifyserverthatthere'
sanewconnection
m_pWndServer->
SendMessage(WM_THREADSTART,(WPARAM)this,0);
if(((CFTPServer*)m_pWndServer)->
CheckMaxUsers())
m_ConnectSocket.SendResponse("
421Toomanyusersareconnected,pleasetryagainlater."
PostThreadMessage(WM_QUIT,0,0);
if(!
((CFTPServer*)m_pWndServer)->
IsIPAddressAllowed(strIPAddress))
421Accessdenied,IPaddresswasrejectedbytheserver."
//sendwelcomemessagetoclient
CStringstrText=((CFTPServer*)m_pWndServer)->
GetWelcomeMessage();
220"
+strText);
m_nTimerID=:
SetTimer(NULL,0,1000,TimerProc);
catch(CException*e)
e->
Delete();
returnTRUE;
线程结束以后,通过ExitInstance函数实现资源的释放代码如下:
intCConnectThread:
ExitInstance()
pWnd->
//deletethisthreadfromthelinkedlist
POSITIONpos=pWnd->
m_ThreadList.Find(this);
if(pos!
pWnd->
m_ThreadList.RemoveAt(pos);
//notifyservicemainloop
SendMessage(WM_THREADCLOSE,(WPARAM)this,0);
returnCWinThread:
ExitInstance();
为了了解传输过程中接收和发送的字节数,使用IncReceivedBytes和IncSentBytes来计算。
这两个函数在CConnectSocket类中调用,代码如下:
voidCConnectThread:
IncSentBytes(intnBytes)
m_LastDataTransferTime=CTime:
GetCurrentTime();
m_nSentBytes+=nBytes;
//notifyserverclass
m_pWndServer->
PostMessage(WM_THREADMSG,(WPARAM)0,(LPARAM)nBytes);
IncReceivedBytes(intnBytes)
m_nReceivedBytes+=nBytes;
PostMessage(WM_THREADMSG,(WPARAM)1,(LPARAM)nBytes);
CConnectSocket类
每个线程都是通过一个CConnectSocket对象m_ConnectSocket来完成数据的接受和发送。
当线程创建成功以后,m_ConnectSocket对象通过OnReceive函数获得数据,然后利用ParseCommand函数来解析其中FTP命令
voidCConnectSocket:
OnReceive(intnErrorCode)
TCHARbuff[BUFFERSIZE];
intnRead=Receive(buff,BUFFERSIZE);
switch(nRead)
case0:
Close();
break;
caseSOCKET_ERROR:
if(GetLastError()!
=WSAEWOULDBLOCK)
TCHARszError[256];
wsprintf(szError,"
OnReceiveerror:
%d"
GetLastError());
AfxMessageBox(szError);
default:
if(nRead!
=SOCKET_ERROR&
&
nRead!
=0)
((CConnectThread*)AfxGetThread())->
IncReceivedBytes(nRead);
//terminatethestring
buff[nRead]=0;
m_RxBuffer+=CString(buff);
GetRxLine();
}
CSocket:
OnReceive(nErrorCode);
ParseCommand函数
是当前程序最重要的一个部分,它根据客户端提交的各种命令进行相应的操作代码如下
ParseCommand()
staticCFTPCommandcommandList[]=
{TOK_USER, "
USER"
TRUE},
{TOK_PASS, "
PASS"
{TOK_CWD, "
CWD"
TRUE},
{TOK_PWD, "
PWD"
FALSE},
{TOK_PORT, "
PORT"
{TOK_PASV, "
PASV"
FALSE},
{TOK_TYPE, "
TYPE"
{TOK_LIST, "
LIST"
{TOK_REST, "
REST"
{TOK_CDUP, "
CDUP"
{TOK_RETR, "
RETR"
{TOK_STOR, "
STOR"
{TOK_SIZE, "
SIZE"
{TOK_DELE, "
DELE"
{TOK_RMD, "
RMD"
{TOK_MKD, "
MKD"
{TOK_RNFR, "
RNFR"
{TOK_RNTO, "
RNTO"
{TOK_ABOR, "
ABOR"
FALSE},
{TOK_SYST, "
SYST"
{TOK_NOOP, "
NOOP"
{TOK_BYE, "
BYE"
FALSE},
{TOK_QUIT, "
QUIT"
{TOK_ERROR, "
"
FALSE},
};
//parsecommand
CStringstrCommand,strArguments;
GetRxCommand(strCommand,strArguments))
intnCommand;
//查找命令
for(nCommand=TOK_USER;
nCommand<
TOK_ERROR;
nCommand++)
//foundcommand?
if(strCommand==commandList[nCommand].m_pszName)
//didweexpectanargument?
if(commandList[nCommand].m_bHasArguments&
(strArguments=="
))
SendResponse("
501Syntaxerror"
return;
if(nCommand=