首先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是一样的