百度中关于CAsyncSocket的介绍
2011-04-13 00:23
232 查看
原文章出处http://baike.baidu.com/view/536039.htm
它是一个异步非阻塞Socket封装类,CAsyncSocket::Create()有一个参数指明了你想要处理哪些Socket事件,你关心的事件被指定以后,这个Socket默认就被用作了异步方式。CAsyncSocket的Create()函数,除了创建了一个SOCKET以外,还创建了个CSocketWnd窗口对象,并使用WSAAsyncSelect()将这个SOCKET与该窗口对象关联,以让该窗口对象处理来自Socket的事件(消息),然而CSocketWnd收到Socket事件之后,只是简单地回调CAsyncSocket::OnReceive()等虚函数。所以CAsyncSocket的派生类,只需要在这些虚函数里添加发送和接收的代码。
它是一个异步非阻塞Socket封装类,CAsyncSocket::Create()有一个参数指明了你想要处理哪些Socket事件,你关心的事件被指定以后,这个Socket默认就被用作了异步方式。CAsyncSocket的Create()函数,除了创建了一个SOCKET以外,还创建了个CSocketWnd窗口对象,并使用WSAAsyncSelect()将这个SOCKET与该窗口对象关联,以让该窗口对象处理来自Socket的事件(消息),然而CSocketWnd收到Socket事件之后,只是简单地回调CAsyncSocket::OnReceive()等虚函数。所以CAsyncSocket的派生类,只需要在这些虚函数里添加发送和接收的代码。
大致的代码为
bool CAsyncSocket::Create( long lEvent ) file://参/数lEvent是指定你所关心的Socket事件 { m_hSocket = socket( PF_INET, SOCK_STREAM, 0 ); file://创/建Socket本身 CSocketWnd* pSockWnd = new CSocketWnd; file://创/建响应事件的窗口,实际的这个窗口在AfxSockInit()调用时就被创建了。 pSockWnd->Create(...); WSAAsyncSelect( m_hSocket, pSockWnd->m_hWnd, WM_SOCKET_NOTIFY, lEvent ); file://Socket/事件和窗口关联 } static void PASCAL CAsyncSocket::DoCallBack(WPARAM wParam, LPARAM lParam) { CAsyncSocket Socket; Socket.Attach( (SOCKET)wParam ); file://wParam/就是触发这个事件的Socket的句柄 int nErrorCode = WSAGETSELECTERROR(lParam); file://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 ); file://收/到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好处
CAsyncSocket类为我们使用Socket提供了极大方便。建立Socket的WSAStartup过程和bind过程被简化成为Create过程,IP地址类型转换、主机名和IP地址转换的过程中许多复杂的变量类型都被简化成字符串和整数操作,特别是CAsyncSocket类的异步特点,完全可以替代繁琐的线程操作。MFC提供了大量的类库,我们若能灵活的使用他们,便会大大提高编程的效率。相关文章推荐
- 百度关于批处理的介绍
- 百度刘杰关于分布式的介绍
- 简单介绍百度与谷歌关于收录的不同之处
- 关于“分贝”单位的介绍,比百度讲的明白多了
- Deque的部分成员函数 解析,关于这个类,百度有很多解析,唯独没有其函数介绍
- 关于 sklearn.decomposition.KernelPCA的简单介绍
- 关于某社交app的安全分析 简单介绍下app防止反编译的方法
- pmp教程【3】关于pmp的考试范围和题型介绍
- 关于Java EE的介绍
- 关于EFLAGS寄存器介绍
- 关于andorid播放内部铃声和震动的简单介绍
- 14-关于Samba配置文件的介绍(转载自网络)
- 关于ArcGIS API for JavaScript中basemap的总结介绍(一)
- 关于面向对象编程与面向过程编程的介绍与解释
- 关于UML建模工具Architexa的介绍
- 关于freeMarker的一些基本介绍~
- 关于require和package.loadlib的介绍和它们的关系,以及它们在加载C模块时不同表现
- iOS开发教程之线程关于多线程的简单介绍
- 关于Class.forName(className).newInstance()介绍
- 关于Iptable的介绍,相当全面: