CAsyncSocket

它是一個異步非阻塞Socket封裝類,CAsyncSocket::Create()有一個參數指明了你想要處理哪些Socket事件,你關心的事件被指定以後,這個Socket默認就被用作了異步方式。CAsyncSocket的Create()函式,除了創建了一個SOCKET以外,還創建了個CSocketWnd視窗對象,並使用WSAAsyncSelect()將這個SOCKET與該視窗對象關聯,以讓該視窗對象處理來自Socket的事件(訊息),然而CSocketWnd收到Socket事件之後,只是簡單地回調CAsyncSocket::OnReceive()等虛函式。所以CAsyncSocket的派生類,只需要在這些虛函數裡添加傳送和接收的代碼。

基本介紹

  • 中文名:CAsyncSocket
  • 好處:極大方便
  • 實質:異步非阻塞Socket封裝類
  • 傳送和接收虛函式
大致的代碼為,特別注意,CAsyncsocket擴展,

大致的代碼為

bool CAsyncSocket::Create( long lEvent ) //參數lEvent是指定你所關心的Socket事件
{
m_hSocket = socket( PF_INET, SOCK_STREAM, 0 ); //創建Socket對象
CSocketWnd* pSockWnd = new CSocketWnd; //創建回響事件的視窗,實際的這個視窗在AfxSockInit()調用時就被創建了。
pSockWnd->Create(...);
WSAAsyncSelect( m_hSocket, pSockWnd->m_hWnd, WM_SOCKET_NOTIFY, lEvent ); //Socket 事件和視窗關聯
}
static void PASCAL CAsyncSocket::DoCallBack(WPARAM wParam, LPARAM lParam)
{
CAsyncSocket*pSocket = CAsyncSocket::LookupHandle((SOCKET)wParam, FALSE); //注意這裡獲取的是已經與m_socketwnd關聯的
int nErrorCode = WSAGETSELECTERROR(lParam); //lParam 是錯誤碼與事件碼的合成
switch (WSAGETSELECTEVENT(lParam))
{
case FD_READ:
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;
}
}
CSocketWnd類大致為:
BEGIN_MESSAGE_MAP(CSocketWnd, CWnd)
ON_MESSAGE(WM_SOCKET_NOTIFY, OnSocketNotify)
END_MESSAGE_MAP()
LRESULT CSocketWnd::OnSocketNotify(WPARAM wParam, LPARAM lParam)
{
CAsyncSocket::DoCallBack( wParam, lParam ); //收到Socket事件訊息,回調CAsyncSocket的DoCallBack()函式
return 0L;
}
然而,最不容易被初學Socket編程的人理解的,也是本文最要提醒的一點是,客戶方在使用CAsyncSocket::Connect()時,往往返回一個WSAEWOULDBLOCK的錯誤(其它的某些函式調用也如此),實際上這不應該算作一個錯誤,它是Socket提醒我們,由於你使用了非阻塞Socket方式,所以(連線)操作需要時間,不能瞬間建立。既然如此,我們可以等待呀,等它連線成功為止,於是許多程式設計師就在調用Connect()之後,Sleep(0),然後不停地用WSAGetLastError()或者CAsyncSocket::GetLastError()查看Socket返回的錯誤,直到返回成功為止。這是一種錯誤的做法,斷言,你不能達到預期目的。事實上,我們可以在Connect()調用之後等待CAsyncSocket::OnConnect()事件被觸發,CAsyncSocket::OnConnect()是要表明Socket要么連線成功了,要么連線徹底失敗了。至此,我們在CAsyncSocket::OnConnect()被調用之後就知道是否Socket連線成功了,還是失敗了。
類似的,Send()如果返回WSAEWOULDBLOCK錯誤,我們在OnSend()處等待,Receive()如果返回WSAEWOULDBLOCK錯誤,我們在OnReceive()處等待,以此類推。

特別注意

還有一點,也許是個難點,那就是在客戶方調用Connect()連線服務方,那么服務方如何Accept(),以建立連線的問題。簡單的做法就是在監聽的Socket收到OnAccept()時,用一個新的CAsyncSocket對象去建立連線,例如:
void CMySocket::OnAccept( int ErrCode )
{
CMySocket* pSocket = new CMySocket;
Accept( *pSocket );
}
於是,上面的pSocket和客戶方建立了連線,以後的通信就是這個pSocket對象去和客戶方進行,而監聽的Socket仍然繼續在監聽,一旦又有一個客戶方要連線服務方,則上面的OnAccept()又會被調用一次。當然pSocket是和客戶方通信的服務方,它不會觸發OnAccept()事件,因為它不是監聽Socket。

CAsyncsocket擴展

Tim kosse 改進了MFC的CAsyncsocket,封裝為CAsyncsocketEx。

相關詞條

熱門詞條

聯絡我們