CAsyncSocketExHelperWindow的消息callback方法是WindowsProc,这是在创建窗口时指定的:
wndclass.lpfnWndProc=WindowProc;
WindowProc处理了5种类型的message
(1) >= WM_SOCKETEX_NOTIFY
(2)WM_USER
CAsyncSocketExLayer用到的消息,如果不使用layer,不会有这个消息
(3) WM_USER+1
(4) WM_USER + 2
(5) WM_TIMER
我们先分析最重要的第一种消息,message>=WM_SOCKETEX_NOTIFY,这个消息是socket上有指定的lEvent发生时,发送来的。使用的windowsapi是WSAAsyncSelect()。
下面条件指定了,如果message大于WM_SOCKETEX_NOTIFY+pWnd->m_nWindowDataSize,就不处理这条消息。
if(message(WM_SOCKETEX_NOTIFY+pWnd->m_nWindowDataSize))
{
...
}
这里,WM_SOCKETEX_NOTIFY是一个基线,即所有socket消息中message都是从WM_SOCKETEX_NOTIFY开始的,CAsyncSocketExHelperWindow的成员变量m_pAsyncSocketExWindowData维护了一个需要分发消息的socket数组,根据FileZilla规则,socket在这个数组中的位置决定了消息的message值。即数组中第0个socket的所有消息message都是WM_SOCKETEX_NOTIFY +0,数组中第1个socket的所有消息message都是WM_SOCKETEX_NOTIFY +1,依次类推,因此如果message大于WM_SOCKETEX_NOTIFY+pWnd->m_nWindowDataSize,实际就意味着这不是一个合法的消息。这里,我们可以看一下create时,调用WSAAsyncSelect时的代码:
if (!WSAAsyncSelect(m_SocketData.hSocket, GetHelperWindowHandle(),m_SocketData.nSocketIndex+WM_SOCKETEX_NOTIFY, lEvent) )
returnTRUE;
参数中,
m_SocketData.hSocket指的是CAsyncSocketEx通过socket()创建的windowssocket,
GetHelperWindowHandle()指的就是CAsyncSocketExHelperWindow,
m_SocketData.nSocketIndex+WM_SOCKETEX_NOTIFY指的就是发送消息的message值,是基数加上在数组中的位置:nSocketIndex
lEvent指的是socket有何种event时,发送消息
往下看消息的处理过程:
CAsyncSocketEx*pSocket=pWnd->m_pAsyncSocketExWindowData[message-WM_SOCKETEX_NOTIFY].m_pSocket;
SOCKET hSocket=wParam;
...
int nEvent=lParam&0xFFFF;
intnErrorCode=lParam>>16;
这里通过message-WM_SOCKETEX_NOTIFY找到这条消息所属的CAsyncSocketEx,这里wParam指定了socket,这其实和pSocket是一回事,两者都对应一个socket,或者说是CAsyncSocketEx。lParam指定发生了何种event。
一般情况下if (!pSocket->m_pFirstLayer)都会成立,即没有m_pFirstLayer,因此我们看if(!pSocket->m_pFirstLayer)对应的代码,
switch (nEvent)
{
...
}
显然是对nEvent进行分析,中间代码有很多
#ifndef NOSOCKETSTATES
#endif//NOSOCKETSTATES
这是用来设置socket状态的,暂时可以忽略,即可以删掉这个中间的代码,整个程序会清爽很多:
switch (nEvent)
{
case FD_READ:
if (pSocket->m_lEvent & FD_READ)
{
DWORD nBytes = 0;
if (!nErrorCode)
if(!pSocket->IOCtl(FIONREAD, &nBytes)) // 看看能读多少个字节
nErrorCode = WSAGetLastError();
if (nBytes != 0 || nErrorCode != 0)
pSocket->OnReceive(nErrorCode);
}
break;
case FD_FORCEREAD: //Forceread does not check if there's data waiting
if (pSocket->m_lEvent & FD_READ)
{
pSocket->OnReceive(nErrorCode);
}
break;
case FD_WRITE:
if (pSocket->m_lEvent & FD_WRITE)
{
pSocket->OnSend(nErrorCode);
}
break;
case FD_CONNECT:
if (pSocket->m_lEvent & FD_CONNECT)
pSocket->OnConnect(nErrorCode);
break;
case FD_ACCEPT:
if (pSocket->m_lEvent & FD_ACCEPT)
pSocket->OnAccept(nErrorCode);
break;
case FD_CLOSE:
pSocket->OnClose(nErrorCode);
break;
}
很清楚,nEvent以下几种类型,分别调用了相应CAsyncSocketEx的On方法:
FD_READ
CAsyncSocketEx::OnReceive
FD_FORCEREAD
CAsyncSocketEx::OnReceive
FD_WRITE
CAsyncSocketEx::OnSend
FD_CONNECT
CAsyncSocketEx::OnConnect
FD_ACCEPT
CAsyncSocketEx::OnAccept
FD_CLOSE
CAsyncSocketEx::OnClose
打开这些On方法看一下,CAsyncSocketEx提供了空的实现,这是合理的,CAsyncSocketEx是基类,它并不清楚应该怎样处理这些消息,这肯定应该由子类来实现这些On方法。
分析了CAsyncSocketEx类以后,我们大致清楚了整个socket处理的机制,下面就要对一个个具体的继承于CAsyncSocketEx的类进行分析,看看到底怎样来处理这些从socket分发来的消息。