本節(jié)的分析是基于本系列第二篇FileZilla Server源碼分析(2)之上,嚴(yán)格意義上來說是更為詳細(xì)的分析,深入了解CAsyncSocketEx的實(shí)現(xiàn),我將挑出重要的函數(shù)一一分析。
函數(shù)名都為紅色粗體,并且?guī)б粚?duì)小括號(hào),如果括號(hào)不含有字符“...”表示該函數(shù)無參數(shù),否則有參數(shù),具體什么參數(shù)不具體指明。變量均為黑色粗體。
首先來看一下該類的構(gòu)造函數(shù)
CAsyncSocketEx(),構(gòu)造函數(shù)完成的是部分成員變量的初始化工作,其中最重要的是一個(gè)結(jié)構(gòu)體變量
m_SocketData,它的原型為:
//Strucure to hold the socket data
struct t_AsyncSocketExData
{
SOCKET hSocket; //Socket handle
int nSocketIndex; //Index of socket, required by CAsyncSocketExHelperWindow
int nFamily;
addrinfo *addrInfo, *nextAddr; // Iterate through protocols on connect failure
bool onCloseCalled; // Set to true on first received OnClose event
} m_SocketData;
還有
m_pLocalAsyncSocketExThreadData的原型為:
//Pointer to the data of the local thread
struct t_AsyncSocketExThreadData
{
CAsyncSocketExHelperWindow *m_pHelperWindow;
int nInstanceCount;
DWORD nThreadId;
std::list<CAsyncSocketEx*> layerCloseNotify;
} *m_pLocalAsyncSocketExThreadData;
每個(gè)成員具體作用注釋已經(jīng)比較清楚地說明了,后面用到的時(shí)候再指出。除了層
NOLAYERS編譯(如果不明白,請(qǐng)看第二篇)此外還有一個(gè)宏條件編譯需要注意
#ifndef NOSOCKETSTATES
m_nPendingEvents = 0; //socket當(dāng)前未決的網(wǎng)絡(luò)事件,例如FD_READ
m_nState = notsock; //socket當(dāng)前狀態(tài)
#endif //NOSOCKETSTATES
析構(gòu)函數(shù)
~CAsyncSocketEx()調(diào)用函數(shù)
Close()關(guān)閉socket,并調(diào)用
FreeAsyncSocketExInstance()做清理工作。
Close()函數(shù)中關(guān)閉層m_pFirstLayer->Close(),之后關(guān)閉成員變量
m_SocketData.hSocket并且從輔助窗口
m_pLocalAsyncSocketExThreadData->m_pHelperWindow記錄中移除掉這個(gè)socket,之后就是銷毀各種資源如地址、代理層等,有一個(gè)細(xì)節(jié),不明白的可以MSDN,不細(xì)說了。
if (m_hAsyncGetHostByNameHandle)
WSACancelAsyncRequest(m_hAsyncGetHostByNameHandle);
m_hAsyncGetHostByNameHandle = NULL;
再說
FreeAsyncSocketExInstance()之前先說對(duì)應(yīng)的函數(shù)InitAsyncSocketExInstance(),這兩個(gè)函數(shù)干的活都和一個(gè)static變量m_spAsyncSocketExThreadDataList有關(guān),一個(gè)初始化,一個(gè)銷毀,m_pLocalAsyncSocketExThreadData保存了當(dāng)前線程的id和輔助窗口的指針。
Create(...)函數(shù)創(chuàng)建代理層或者自身的socket以及做綁定到輔助窗口等操作。如果定義了使用代理層,那么所有關(guān)于socket的操作都會(huì)被代理層攔截,如create,listen,connect,accpet,recv,send,但是不包括bind,因?yàn)榇韺觕reate的時(shí)候已經(jīng)提前綁定過了。
TriggerEvent(...)這個(gè)函數(shù)用來觸發(fā)程序員指定的網(wǎng)絡(luò)事件,例如CControlSocket類中的
Send(...)函數(shù)就調(diào)用了
TriggerEvent(FD_WRITE)來觸發(fā)寫操作。它通過PosetMessage給輔助窗口,然后窗口通過消息處理函數(shù)
WindowProc(...)處理這種種消息(詳細(xì)請(qǐng)
參考第二節(jié))。
與代理層相關(guān)的函數(shù),如
AddLayer(...),
RemoveAllLayers()等,還有設(shè)置獲取各種信息的函數(shù)如GetSockOpt()就不在詳述了。
下面再補(bǔ)充之前函數(shù)
WindowProc(...)關(guān)于網(wǎng)絡(luò)事件的詳細(xì)處理,僅僅針對(duì)非代理層的處理:
//if (!pSocket->m_pFirstLayer)
//{
switch (nEvent)
{
case FD_READ:
if (pSocket->GetState() == connecting && !nErrorCode)
{
pSocket->m_nPendingEvents |= FD_READ; //如果正在連接,那么將讀事件加入未決事件變量里
break;
}
else if (pSocket->GetState() == attached)//已綁定成功的設(shè)置為連接成功
pSocket->SetState(connected);
if (pSocket->GetState() != connected) //如果還沒有連接成功,跳出
break;
// Ignore further FD_READ events after FD_CLOSE has been received
if (pSocket->m_SocketData.onCloseCalled)
break;
if (pSocket->m_lEvent & FD_READ)
{
DWORD nBytes = 0;
if (!nErrorCode)
if (!pSocket->IOCtl(FIONREAD, &nBytes)) //獲取要可讀的字節(jié)數(shù)
nErrorCode = WSAGetLastError();
if (nErrorCode)
pSocket->SetState(aborted); //出錯(cuò)
if (nBytes != 0 || nErrorCode != 0) //通知socket已經(jīng)有數(shù)據(jù)可以讀了
pSocket->OnReceive(nErrorCode);
}
break;
case FD_FORCEREAD:
//除了不用獲取去可讀的字節(jié)數(shù)之外,完全可FD_READ一樣,這是作者自定義的類型
break;
case FD_WRITE:
//前面的狀態(tài)判斷和FD_READ類似,不再詳述
if (pSocket->m_lEvent & FD_WRITE)
{
if (nErrorCode)
pSocket->SetState(aborted);
pSocket->OnSend(nErrorCode);//通知socket已經(jīng)有數(shù)據(jù)可以發(fā)送了
}
break;
case FD_CONNECT:
if (pSocket->GetState() == connecting)
{
if (nErrorCode && pSocket->m_SocketData.nextAddr) //有多個(gè)地址?
{
if (pSocket->TryNextProtocol()) //嘗試下一個(gè)協(xié)議地址
break;
}
pSocket->SetState(connected);
}
else if (pSocket->GetState() == attached && !nErrorCode)
pSocket->SetState(connected);
if (pSocket->m_lEvent & FD_CONNECT)
pSocket->OnConnect(nErrorCode);
if (!nErrorCode)
{
//判斷未決事件中是否期望的讀寫事件,如果有,通知socket
if ((pSocket->m_nPendingEvents&FD_READ) && pSocket->GetState() == connected)
pSocket->OnReceive(0);
if ((pSocket->m_nPendingEvents&FD_FORCEREAD) && pSocket->GetState() == connected)
pSocket->OnReceive(0);
if ((pSocket->m_nPendingEvents&FD_WRITE) && pSocket->GetState() == connected)
pSocket->OnSend(0);
}
pSocket->m_nPendingEvents = 0;
break;
case FD_ACCPET:
//如果不是監(jiān)聽或已經(jīng)綁定狀態(tài),跳出
if (pSocket->GetState() != listening && pSocket->GetState() != attached)
break;
if (pSocket->m_lEvent & FD_ACCEPT)
pSocket->OnAccept(nErrorCode);//通知
break;
case FD_CLOSE:
//沒有連接或綁定,跳出
if (pSocket->GetState() != connected && pSocket->GetState() != attached)
break;
// If there are still bytes left to read, call OnReceive instead of
// OnClose and trigger a new OnClose
DWORD nBytes = 0;
if (!nErrorCode && pSocket->IOCtl(FIONREAD, &nBytes))
{
//作者的注釋很清楚,如果關(guān)閉的時(shí)候還有數(shù)據(jù)可讀,將當(dāng)前pSocket->m_SocketData.onCloseCalled 設(shè)置為TRUE
//以表示需要再一次調(diào)用關(guān)閉函數(shù)OnClose
if (nBytes > 0)
{
// Just repeat message.
PostMessage(hWnd, message, wParam, lParam);
pSocket->m_SocketData.onCloseCalled = true;
pSocket->OnReceive(WSAESHUTDOWN);
break;
}
}
pSocket->SetState(nErrorCode?aborted:closed);
pSocket->OnClose(nErrorCode);
break;
}
//}
本節(jié)是對(duì)第二節(jié)的一個(gè)小補(bǔ)充,也算是對(duì)MS的CAsyncSocket類的一個(gè)另類剖析吧。