FileZilla 源代碼分析4
FileZilla是一種快速、可信賴的FTP客戶端以及服務(wù)器端開放源代碼程式,具有多種特色、直覺的接口。本文就給大家分析下FileZilla的源代碼。
< type="text/javascript"> < src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"> < type="text/javascript"> < src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript">
CServer在Create()時,通過CListenSocket來監(jiān)聽標(biāo)準(zhǔn)的FTP 21端口,通過CAdminListenSocket來監(jiān)聽admin端口(缺省是14147),這兩個類都繼承于CAsyncSocketEx,這個類是FileZilla中所有socket處理的基類,搞清楚這個類可以清楚明白socket處理的機(jī)制。
這個類的名字來源于MFC類CAsyncSocket,CAsyncSocketEx完全兼容于CAsyncSocket,在CAsyncSocket上寫的代碼可以一字不動的在CAsyncSocketEx下編譯通過,CAsyncSocketEx還做了一些功能上的擴(kuò)展和性能上的優(yōu)化。
CAsyncSocketEx和另兩個類CAsyncSocketExHelperWindow以及CAsyncSocketExLayer緊密相關(guān),CAsyncSocketExLayer的作用類似于J2EE中的Interceptor的作用,這里可以先不討論。
CAsyncSocketEx采用的是消息處理的機(jī)制,即監(jiān)聽的端口有活動,如有數(shù)據(jù)要接收、發(fā)送等,通過發(fā)送消息來實(shí)現(xiàn)這種信息的通訊,這里具體到windows socket的API就是WSAAsyncSelect,它的原型是:
int WSAAsyncSelect(
SOCKET s,
HWND hWnd,
unsigned int wMsg,
long lEvent
);
Parameters
s
[in] Descriptor identifying the socket for which event notification is required.
hWnd
[in] Handle identifying the window that will receive a message when a network event occurs.
wMsg
[in] Message to be received when a network event occurs.
lEvent
[in] Bitmask that specifies a combination of network events in which the application is interested.
簡單地說,這個方法可以讓windows在SOCKET s指定的socket上,當(dāng)指定的事件lEvent發(fā)生時,發(fā)送消息wMsg到窗口hWnd。
由于windows的消息機(jī)制必須使用一個windows窗口,因此CAsyncSocketEx必須創(chuàng)建一個windows窗口來接收這種消息,這就是類CAsyncSocketExHelperWindow的主要作用,當(dāng)然這個窗口并不是必須被顯示出來的,只要讓系統(tǒng)知道有這個windows存在(即有hWnd)就可以了。
在CAsyncSocketEx中,定義了一個static的鏈表:
static struct t_AsyncSocketExThreadDataList
{
t_AsyncSocketExThreadDataList *pNext;
t_AsyncSocketExThreadData *pThreadData;
} *m_spAsyncSocketExThreadDataList;
這個鏈表維護(hù)了一個t_AsyncSocketExThreadData鏈,看一下這個struct的定義:
struct t_AsyncSocketExThreadData
{
CAsyncSocketExHelperWindow *m_pHelperWindow;
int nInstanceCount;
DWORD nThreadId;
std::list layerCloseNotify;
} *m_pLocalAsyncSocketExThreadData;
看名稱就知道,這是一個與線程thread有關(guān)的結(jié)構(gòu),事實(shí)上這個結(jié)構(gòu)描述了一個分發(fā)線程。
在FileZilla的實(shí)現(xiàn)中,整個靜態(tài)的類關(guān)系是這樣的:
一個CAsyncSocketEx代表了一個socket,即在某個端口進(jìn)行監(jiān)聽的socket,如前面提到的標(biāo)準(zhǔn)的FTP 21端口、admin端口等等。
一個CAsyncSocketExHelperWindow代表了一個負(fù)責(zé)消息分發(fā)的線程,即負(fù)責(zé)接收到socket(CAsyncSocketEx)的活動,然后分發(fā)到不同的處理類CAsyncSocketEx。每一個CAsyncSocketExHelperWindow一一對應(yīng)于一個分發(fā)線程,即一個分發(fā)線程只有一個CAsyncSocketExHelperWindow,反之亦然。結(jié)構(gòu)t_AsyncSocketExThreadData即描述了分發(fā)線程與CAsyncSocketExHelperWindow的關(guān)系。
CAsyncSocketExHelperWindow可以為多個CAsyncSocketEx進(jìn)行分發(fā),而CAsyncSocketEx只能由一個CAsyncSocketExHelperWindow進(jìn)行分發(fā)?,F(xiàn)在仔細(xì)研究一下結(jié)構(gòu)t_AsyncSocketExThreadData:
struct t_AsyncSocketExThreadData
{
CAsyncSocketExHelperWindow *m_pHelperWindow; // 這個線程對應(yīng)的CAsyncSocketExHelperWindow
int nInstanceCount; // 當(dāng)前分發(fā)線程對應(yīng)了幾個CAsyncSocketEx
DWORD nThreadId; // 當(dāng)前線程的threadID
std::list layerCloseNotify; // 這個以后再說
} *m_pLocalAsyncSocketExThreadData;
這段代碼是在類CAsyncSocketEx中定義的,即m_pLocalAsyncSocketExThreadData定義了當(dāng)前CAsyncSocketEx所對應(yīng)的分發(fā)線程,即CAsyncSocketExHelperWindow。
全局的m_spAsyncSocketExThreadDataList則定義了一個t_AsyncSocketExThreadData(即分發(fā)線程)的鏈表,也就是說FileZilla可以有多個分發(fā)線程,每個分發(fā)線程對應(yīng)多個socket,即CAsyncSocketEx。
舉一個實(shí)際的場景:
在FileZilla Server啟動時,缺省監(jiān)聽了兩個端口:21和admin端口,因此就有兩個socket,即兩個CAsyncSocketEx。
這兩個CAsyncSocketEx共用一個分發(fā)線程:t_AsyncSocketExThreadData
當(dāng)有用戶通過FTP連接上server并通過get/mget命令下載文件時,這時FTP服務(wù)器會啟動一個傳輸線程在一個臨時端口進(jìn)行監(jiān)聽,這時會增加一個CAsyncSocketEx,同時也增加一個負(fù)責(zé)這個CAsyncSocketEx的分發(fā)線程,因此m_spAsyncSocketExThreadDataList里也會增加一個結(jié)點(diǎn)。
這時的狀況是:
一個m_spAsyncSocketExThreadDataList鏈,兩個t_AsyncSocketExThreadData,三個CAsyncSocketEx。
通過文章完整的描述,大家應(yīng)該知道了FileZilla 源代碼,希望對大家有幫助!
【編輯推薦】