浅析CAsyncSocket

    首先CAsyncSocket采用的WSAAsynSelect模型,WSAAsynSelect是一种异步I/O模型,通过该模型,应用程序可以接收以Windows消息为基础的网络事件通知。而我们这里讲的就是CSocketWnd,它是从CWnd继承的。

class CSocketWnd : public CWnd { public: CSocketWnd(); protected: LRESULT OnSocketNotify(WPARAM wParam, LPARAM lParam); LRESULT OnSocketDead(WPARAM wParam, LPARAM lParam); DECLARE_MESSAGE_MAP() };

从源码中看出它只处理两个消息,一个是WM_SOCKET_NOTIFY,另一个是WM_SOCKET_DEAD。

 

我原以为没创建一个Socket就会创建一个CSocketWnd,其实不是,是所有的Socket共享一个CSocketWnd,其实想想也是,要是每创建一个Socket就创建一个CSocketWnd那开销也大了点。

 

既然是共享的,那它放在哪里呢?

全局中有这样一个结构体:_AFX_SOCK_THREAD_STATE,它保存一个那个共享的窗口句柄:m_hSocketWindow。

当没有创建Socket时,它是Null的。

除了m_hSocketWindow结构体_AFX_SOCK_THREAD_STATE还有几个重要的变量:

1. mCEmbeddedButActsLikePtr<CMapPtrToPtr> m_pmapSocketHandle:记录了CAysncSocket*与没死的SOCKET的映射关系

2. CEmbeddedButActsLikePtr<CMapPtrToPtr> m_pmapDeadSockets:记录了SOCKET与死了的次数的映射关系

3. CEmbeddedButActsLikePtr<CPtrList> m_plistSocketNotifications:记录的所有的SOCKET事件的通知消息

 

每当调用Attach时,Attach调用AttachHandle,在AttachHandle把一个CAysncSocket*和SOCKET加入m_pmapSocketHandle中,

当调用Socket时也会调用AttachHandle,与之对于是Detach.

 

当一个非死亡事件发生时,会向m_hSocketWindow发送WM_SOCKET_NOTIFY,其消息处理函数如下

LRESULT CSocketWnd::OnSocketNotify(WPARAM wParam, LPARAM lParam) { CSocket::AuxQueueAdd(WM_SOCKET_NOTIFY, wParam, lParam); CSocket::ProcessAuxQueue(); return 0L; }

 


CSocket::AuxQueueAdd(WM_SOCKET_NOTIFY, wParam, lParam);源码如下:

void PASCAL CSocket::AuxQueueAdd(UINT message, WPARAM wParam, LPARAM lParam) { _AFX_SOCK_THREAD_STATE* pState = _afxSockThreadState; MSG* pMsg = new MSG; pMsg->message = message; pMsg->wParam = wParam; pMsg->lParam = lParam; pState->m_plistSocketNotifications->AddTail(pMsg); }

接到消息以后把它放入:m_plistSocketNotification中

 

CSocket::ProcessAuxQueue(WM_SOCKET_NOTIFY, wParam, lParam);源码如下:

int PASCAL CSocket::ProcessAuxQueue() { _AFX_SOCK_THREAD_STATE* pState = _afxSockThreadState; if (pState->m_plistSocketNotifications->IsEmpty()) return 0; int nCount = 0; while(!pState->m_plistSocketNotifications->IsEmpty()) { nCount++; MSG* pMsg = (MSG*)pState->m_plistSocketNotifications->RemoveHead(); ASSERT(pMsg != NULL); //如果是是WM_SOCKET_NOTIFY调用CAsyncSocket::DoCallBack if (pMsg->message == WM_SOCKET_NOTIFY) { CAsyncSocket::DoCallBack(pMsg->wParam, pMsg->lParam); } //如果是死亡事件执行以下代码 else { ASSERT(CAsyncSocket::LookupHandle((SOCKET)pMsg->wParam, TRUE) != NULL); CAsyncSocket::DetachHandle((SOCKET)pMsg->wParam, TRUE); } delete pMsg; } return nCount; }

从中考研看出最终调用的是:CAsyncSocket::DoCallBack,源码如下:

void PASCAL CAsyncSocket::DoCallBack(WPARAM wParam, LPARAM lParam) { if (wParam == 0 && lParam == 0) return; // Has the socket be closed - lookup in dead handle list CAsyncSocket* pSocket = CAsyncSocket::LookupHandle((SOCKET)wParam, TRUE); // If yes ignore message if (pSocket != NULL) return; pSocket = CAsyncSocket::LookupHandle((SOCKET)wParam, FALSE); if (pSocket == NULL) { // Must be in the middle of an Accept call pSocket = CAsyncSocket::LookupHandle(INVALID_SOCKET, FALSE); ENSURE(pSocket != NULL); if(pSocket == NULL) return; pSocket->m_hSocket = (SOCKET)wParam; CAsyncSocket::DetachHandle(INVALID_SOCKET, FALSE); CAsyncSocket::AttachHandle(pSocket->m_hSocket, pSocket, FALSE); } int nErrorCode = WSAGETSELECTERROR(lParam); switch (WSAGETSELECTEVENT(lParam)) { case FD_READ: { fd_set fds; int nReady; timeval timeout; timeout.tv_sec = 0; timeout.tv_usec = 0; FD_ZERO(&fds); FD_SET(pSocket->m_hSocket, &fds); nReady = select(0, &fds, NULL, NULL, &timeout); if (nReady == SOCKET_ERROR) nErrorCode = WSAGetLastError(); if ((nReady == 1) || (nErrorCode != 0)) pSocket->OnReceive(nErrorCode); } break; case FD_WRITE: pSocket->OnSend(nErrorCode); break; case FD_OOB: pSocket->OnOutOfBandData(nErrorCode); break; case FD_ACCEPT: pSocket->OnAccept(nErrorCode); break; case FD_CONNECT: pSocket->OnConnect(nErrorCode); break; case FD_CLOSE: pSocket->OnClose(nErrorCode); break; } }

 

消息WM_SOCKET_DEAD处理函数与WM_SOCKET_NOTIFY是一样的

 

从中考研清楚的看出CAsyncSocket的事件处理过程。

以上一定会有一些错误,请各位路过的大侠指正,不胜感激。

 

 

你可能感兴趣的:(thread,windows,socket,null,delete,pascal)