浅析CAsyncSocket

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

[cpp]  view plain copy
  1. class CSocketWnd : public CWnd  
  2. {  
  3. public:  
  4.     CSocketWnd();  
  5. protected:  
  6.     LRESULT OnSocketNotify(WPARAM wParam, LPARAM lParam);  
  7.     LRESULT OnSocketDead(WPARAM wParam, LPARAM lParam);  
  8.     DECLARE_MESSAGE_MAP()  
  9. };  

从源码中看出它只处理两个消息,一个是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,其消息处理函数如下

[cpp]  view plain copy
  1. LRESULT CSocketWnd::OnSocketNotify(WPARAM wParam, LPARAM lParam)  
  2. {  
  3.     CSocket::AuxQueueAdd(WM_SOCKET_NOTIFY, wParam, lParam);  
  4.     CSocket::ProcessAuxQueue();  
  5.     return 0L;  
  6. }  

 


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

[cpp]  view plain copy
  1. void PASCAL CSocket::AuxQueueAdd(UINT message, WPARAM wParam, LPARAM lParam)  
  2. {  
  3.     _AFX_SOCK_THREAD_STATE* pState = _afxSockThreadState;  
  4.     MSG* pMsg = new MSG;  
  5.     pMsg->message = message;  
  6.     pMsg->wParam = wParam;  
  7.     pMsg->lParam = lParam;  
  8.     pState->m_plistSocketNotifications->AddTail(pMsg);  
  9. }  

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

 

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

[cpp]  view plain copy
  1. int PASCAL CSocket::ProcessAuxQueue()  
  2. {  
  3.     _AFX_SOCK_THREAD_STATE* pState = _afxSockThreadState;  
  4.     if (pState->m_plistSocketNotifications->IsEmpty())  
  5.         return 0;  
  6.     int nCount = 0;  
  7.     while(!pState->m_plistSocketNotifications->IsEmpty())  
  8.     {  
  9.         nCount++;  
  10.         MSG* pMsg = (MSG*)pState->m_plistSocketNotifications->RemoveHead();  
  11.         ASSERT(pMsg != NULL);  
  12.         //如果是是WM_SOCKET_NOTIFY调用CAsyncSocket::DoCallBack  
  13.         if (pMsg->message == WM_SOCKET_NOTIFY)  
  14.         {  
  15.             CAsyncSocket::DoCallBack(pMsg->wParam, pMsg->lParam);  
  16.         }  
  17.         //如果是死亡事件执行以下代码  
  18.         else  
  19.         {  
  20.             ASSERT(CAsyncSocket::LookupHandle((SOCKET)pMsg->wParam, TRUE) != NULL);  
  21.             CAsyncSocket::DetachHandle((SOCKET)pMsg->wParam, TRUE);  
  22.         }  
  23.         delete pMsg;  
  24.     }  
  25.     return nCount;  
  26. }  

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

[cpp]  view plain copy
  1. void PASCAL CAsyncSocket::DoCallBack(WPARAM wParam, LPARAM lParam)  
  2. {  
  3.     if (wParam == 0 && lParam == 0)  
  4.         return;  
  5.     // Has the socket be closed - lookup in dead handle list  
  6.     CAsyncSocket* pSocket = CAsyncSocket::LookupHandle((SOCKET)wParam, TRUE);  
  7.     // If yes ignore message  
  8.     if (pSocket != NULL)  
  9.         return;  
  10.     pSocket = CAsyncSocket::LookupHandle((SOCKET)wParam, FALSE);  
  11.     if (pSocket == NULL)  
  12.     {  
  13.         // Must be in the middle of an Accept call  
  14.         pSocket = CAsyncSocket::LookupHandle(INVALID_SOCKET, FALSE);  
  15.         ENSURE(pSocket != NULL);  
  16.         if(pSocket == NULL)  
  17.             return;  
  18.               
  19.         pSocket->m_hSocket = (SOCKET)wParam;  
  20.         CAsyncSocket::DetachHandle(INVALID_SOCKET, FALSE);  
  21.         CAsyncSocket::AttachHandle(pSocket->m_hSocket, pSocket, FALSE);  
  22.     }  
  23.     int nErrorCode = WSAGETSELECTERROR(lParam);  
  24.     switch (WSAGETSELECTEVENT(lParam))  
  25.     {  
  26.     case FD_READ:  
  27.         {  
  28.             fd_set fds;  
  29.             int nReady;  
  30.             timeval timeout;  
  31.             timeout.tv_sec = 0;  
  32.             timeout.tv_usec = 0;  
  33.             FD_ZERO(&fds);  
  34.             FD_SET(pSocket->m_hSocket, &fds);  
  35.             nReady = select(0, &fds, NULL, NULL, &timeout);  
  36.             if (nReady == SOCKET_ERROR)  
  37.                 nErrorCode = WSAGetLastError();  
  38.             if ((nReady == 1) || (nErrorCode != 0))  
  39.                 pSocket->OnReceive(nErrorCode);  
  40.         }  
  41.         break;  
  42.     case FD_WRITE:  
  43.         pSocket->OnSend(nErrorCode);  
  44.         break;  
  45.     case FD_OOB:  
  46.         pSocket->OnOutOfBandData(nErrorCode);  
  47.         break;  
  48.     case FD_ACCEPT:  
  49.         pSocket->OnAccept(nErrorCode);  
  50.         break;  
  51.     case FD_CONNECT:  
  52.         pSocket->OnConnect(nErrorCode);  
  53.         break;  
  54.     case FD_CLOSE:  
  55.         pSocket->OnClose(nErrorCode);  
  56.         break;  
  57.     }  
  58. }  

 

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

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值