FileZilla 源代碼分析10
FileZilla是一種快速、可信賴的FTP客戶端以及服務(wù)器端開放源代碼程式,具有多種特色、直覺的接口。本文就給大家分析下FileZilla的源代碼。
前面已經(jīng)分析過了FTP客戶登錄服務(wù)器的過程,現(xiàn)在來看一下常見的ls命令的處理過程。
用戶在FTP客戶端輸入ls命令后,ftp.exe首先發(fā)出port請求給服務(wù)器,在CControlSocket的ParseCommand()中被處理。
PORT命令的參數(shù)是形如:127.0.0.1.4.9,前4個(gè)表示客戶端的IP地址,后兩個(gè)根據(jù)規(guī)則4 * 256 + 9 = 1033,表示FTP客戶端臨時(shí)建立的用來與服務(wù)器建立數(shù)據(jù)連接的端口,例子所示為1033端口。
PORT命令的處理過程的代碼中前面都是用來獲取IP和臨時(shí)端口的:
case COMMAND_PORT:
...
port += 256 * _ttoi(args.Right(args.GetLength() - (i + 1))); // add ms byte to server socket
ip = args.Left(i);
...
下面:
m_transferstatus.ip = ip;
m_transferstatus.port = port;
m_transferstatus.pasv = 0;
Send(_T("200 Port command successful"));
break;
只是將FTP客戶端提供的臨時(shí)端口記錄到m_transferstatus中,然后發(fā)出200 Port command successful,等待FTP客戶端的下一個(gè)命令。由于用戶輸入的是ls命令,ftp.exe在PORT之后,發(fā)出NLST命令。
在case COMMAND_NLST的處理中,先是進(jìn)行了一系列的參數(shù)、權(quán)限檢查,一切OK后:
if (!m_transferstatus.pasv) // 主動(dòng)模式
{
...
}
else // 被動(dòng)模式
{
...
}
由于主動(dòng)模式是缺省值,因此看一下里面的代碼:
CTransferSocket *transfersocket = new CTransferSocket(this);
m_transferstatus.socket = transfersocket;
transfersocket->Init(pResult, TRANSFERMODE_NLST); // 只是一些參數(shù)的初始化
if (m_transferMode == mode_zlib) // 傳輸方式是否使用壓縮方式,缺省不使用,詳細(xì)參見FTP規(guī)范
{
if (!transfersocket->InitZLib(m_zlibLevel))
{
Send(_T("550 could not initialize zlib, please use MODE S instead"));
ResetTransferstatus();
break;
}
}
if (!CreateTransferSocket(transfersocket)) // 建立數(shù)據(jù)連接
break;
SendTransferinfoNotification(TRANSFERMODE_LIST, physicalDir, logicalDir); // Use TRANSFERMODE_LIST instead of TRANSFERMODE_NLST.
Send(_T("150 Opening data channel for directory list."));
先看一下建立數(shù)據(jù)連接的代碼:
BOOL CControlSocket::CreateTransferSocket(CTransferSocket *pTransferSocket)
{
...
if (pTransferSocket->Connect(m_transferstatus.ip,m_transferstatus.port)==0)
...
}
無非是常規(guī)的socket方法建立連接,需要關(guān)注的是由服務(wù)主動(dòng)發(fā)起連接,這正是主動(dòng)模式的含義。我們先看完這一段,再看一下被動(dòng)模式。
在CreateTransferSocket()完成后,調(diào)用:
SendTransferinfoNotification(TRANSFERMODE_LIST, physicalDir, logicalDir);
看一下里面:
void CControlSocket::SendTransferinfoNotification(const char transfermode, const CStdString& physicalFile, const CStdString& logicalFile, __int64 startOffset, __int64 totalSize)
{
t_connop *op = new t_connop;
op->op = USERCONTROL_CONNOP_TRANSFERINIT;
op->userid = m_userid;
t_connectiondata_transferinfo *conndata = new t_connectiondata_transferinfo;
conndata->transferMode = transfermode;
conndata->physicalFile = physicalFile;
conndata->logicalFile = logicalFile;
conndata->startOffset = startOffset;
conndata->totalSize = totalSize;
op->data = conndata;
m_pOwner->SendNotification(FSM_CONNECTIONDATA, (LPARAM)op);
}
可 見發(fā)送了一個(gè)消息給CServer,wParam參數(shù)是FSM_CONNECTIONDATA,表示這是跟connection相關(guān)的消息,lParam 帶的參數(shù)是USERCONTROL_CONNOP_TRANSFERINIT,表示傳輸開始或結(jié)束,我回去看一下CServer中的 OnServerMessage()相關(guān)代碼,在admin窗口的下面顯示了將用傳輸?shù)男畔ⅰ?/p>
下面,
Send(_T("150 Opening data channel for directory list."));
發(fā)送給FTP客戶端數(shù)據(jù)連接創(chuàng)建的消息,真正的數(shù)據(jù)傳輸?shù)娜蝿?wù)是交給數(shù)據(jù)連接了,即CTransferSocket。
我們回到被動(dòng)模式,如果是被動(dòng)模式:
if (!m_transferstatus.pasv)
{
...
}
else // 被動(dòng)模式
{
...
m_transferstatus.socket->PasvTransfer();
}
看一下PasvTransfer()的實(shí)現(xiàn):
void CTransferSocket::PasvTransfer()
{
if(bAccepted)
if (!m_bStarted)
InitTransfer(FALSE);
}
非常簡單,由于是被動(dòng)模式,即由客戶端發(fā)起數(shù)據(jù)連接,因此CTransferSocket只需等待客戶端的連接就可以了,下面分析CTransferSocket的時(shí)候再仔細(xì)看一下相關(guān)的實(shí)現(xiàn)。
通過文章完整的描述,大家應(yīng)該知道了FileZilla 源代碼,希望對(duì)大家有幫助!
【編輯推薦】