以下是MFC 在vc10中实际的代码及我给出的注解,更具说明意义可以看到套接字的创建与窗口绑定过程,以及DoCallBack如何处理收到的消息:
1)BOOL CAsyncSocket::Create(UINT nSocketPort, int nSocketType,
long lEvent, LPCTSTR lpszSocketAddress)
{
if (Socket(nSocketType, lEvent))
{
if (Bind(nSocketPort,lpszSocketAddress))//HY:为套接字绑定地址
return TRUE;
int nResult = GetLastError();
Close();
WSASetLastError(nResult);
}
return FALSE;
}
2)BOOL CAsyncSocket::Socket(int nSocketType, long lEvent,
int nProtocolType, int nAddressFormat)
{
ASSERT(m_hSocket == INVALID_SOCKET);
m_hSocket = socket(nAddressFormat,nSocketType,nProtocolType);
if (m_hSocket != INVALID_SOCKET)//HY:套接字有效则加入活动套接字,字典(套接字,套接字对象,是否是死套接字(非活动的)。
{
CAsyncSocket::AttachHandle(m_hSocket, this, FALSE);
return AsyncSelect(lEvent); //HY:注意这句实现了套接字,窗口,消息,事件的绑定
}
return FALSE;
}
3)void PASCAL CAsyncSocket::AttachHandle(
SOCKET hSocket, CAsyncSocket* pSocket, BOOL bDead)//HY:bDead 为TRUE时证明是一个非活动的套接字。
{
_AFX_SOCK_THREAD_STATE* pState = _afxSockThreadState;
BOOL bEnable = AfxEnableMemoryTracking(FALSE);
TRY
{
if (!bDead) //HY:如果是一个活动的“活”套接字
{
ASSERT(CAsyncSocket::LookupHandle(hSocket, bDead) == NULL);//HY:从MAP(字典结构)中找指定的对象元素
if (pState->m_pmapSocketHandle->IsEmpty())
{
ASSERT(pState->m_pmapDeadSockets->IsEmpty());
ASSERT(pState->m_hSocketWindow == NULL);
CSocketWnd* pWnd = new CSocketWnd; //HY: 构建一个SOCKETWND对象
pWnd->m_hWnd = NULL;
if (!pWnd->CreateEx(0, AfxRegisterWndClass(0),
_T("Socket Notification Sink"),
WS_OVERLAPPED, 0, 0, 0, 0, NULL, NULL)) //HY: SOCKETWND对象
的窗口m_hWnd句柄装载
{
TRACE(traceSocket, 0, "Warning: unable to create socket notify window!\n");
delete pWnd;
AfxThrowResourceException();
}
ASSERT(pWnd->m_hWnd != NULL);
ASSERT(CWnd::FromHandlePermanent(pWnd->m_hWnd) == pWnd); //HY: FromHandlePermanent从指定句柄中得到对象实例
pState->m_hSocketWindow = pWnd->m_hWnd;
}
pState->m_pmapSocketHandle->SetAt((void*)hSocket, pSocket);//HY:字典结构添加socket(套接字值)与CAsyncSocket实例的对应关系。
}
else //HY:如果是一个非活动套接字
{
void* pvCount;
INT_PTR nCount;
if (pState->m_pmapDeadSockets->Lookup((void*)hSocket, pvCount))
{
nCount = (INT_PTR)pvCount;
nCount++;
}
else
nCount = 1;
pState->m_pmapDeadSockets->SetAt((void*)hSocket, (void*)nCount);
}
}
CATCH_ALL (e)
{
AfxEnableMemoryTracking(bEnable);
THROW_LAST();
}
END_CATCH_ALL
AfxEnableMemoryTracking(bEnable);
}
//HY:ATTACH先完成对象中套接字的赋值然后调用了AttachHandle和AsyncSelect
4)BOOL CAsyncSocket::Attach(SOCKET hSocket, long lEvent)
{
ASSERT(hSocket != INVALID_SOCKET);
if (hSocket == INVALID_SOCKET)
{
WSASetLastError (WSA_INVALID_HANDLE);
return FALSE;
}
m_hSocket = hSocket;
CAsyncSocket::AttachHandle(hSocket, this);
return AsyncSelect(lEvent);
}
5)BOOL CAsyncSocket::AsyncSelect(long lEvent)
{
ASSERT(m_hSocket != INVALID_SOCKET);
_AFX_SOCK_THREAD_STATE* pState = _afxSockThreadState;
ASSERT(pState->m_hSocketWindow != NULL);
return WSAAsyncSelect(m_hSocket, pState->m_hSocketWindow,
WM_SOCKET_NOTIFY, lEvent) != SOCKET_ERROR; //HY:完成套接字、窗口、消息类型、事件绑定。
}
6)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); //HY:在存活字典中查找
if (pSocket == NULL)
{
// Must be in the middle of an Accept call
pSocket = CAsyncSocket::LookupHandle(INVALID_SOCKET, FALSE);
ASSERT(pSocket != NULL);
if(pSocket == NULL)
return;
pSocket->m_hSocket = (SOCKET)wParam; //HY:对CAsyncSocket对象的m_hSocket赋当前套接字值
CAsyncSocket::DetachHandle(INVALID_SOCKET, FALSE); //HY:失效套接字字典结构,中去掉当前对象
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;
}
}
以上就实现了套接字的创建及窗口建立,以及消息处理