您的位置:首页 > 其它

CAsyncSocket

2009-03-18 19:37 288 查看
这几天都在研么MFC的套接字类CAsyncSocket的用法, 将一些心得和实践中遇到的问题总结一下。

一、 一些网络的基本概念

1. 同步:指的是发送方不等接收方响应,便接着发下个数据包的通信方式;

2. 异步:指发送方发出数据后,等收到接收方发回的响应,才发下一个数据包的通信方式

3. 阻塞:指调用某函数时,直到该函数完成操作,才返回;否则一直阻塞在该调用上

4. 非阻塞:指调用某操作时,不管操作是否成功都立即返回,而不会挂在该操作上

CAsyncSocket属于异步非阻塞类;

CSocket是MFC在CAsyncSocket基础上派生的一个同步阻塞Socket的封装类

二、 CAsyncSocket的使用(伪码)

服务器端:

m_pListSocket = new CAsyncSocket();

m_pListSocket-> Create( 端口,地址); // 创建

m_pListSocket->Listen(); // 开始监听

m_pListSocket::OnAccept( ) // 有客户端请求连接时响应

m_pSocket::OnRecive( int nErrorCode)

m_pSocket::OnSend()

m_pListSocket->Close();

delete m_pListSocket;

delete m_pSocket;

客户端:

m_pClientSocket = new CAsyncSocket();

m_pClientSocket -> Create( 端口,地址); // 创建

m_pClientSocket->Connect(); // 连接服务器,最终将触发服务器的OnAccept();

m_ pClientSocket::OnConnect() // 当连接上服务器

m_ pClientSocket::OnRecive( int nErrorCode)

m_pClientSocket::OnSend( int nErrorCode)

m_pClientSocket->Close();

三、 CAsyncSocket异步机制

由于CAsyncSocket采用的是异步非阻塞机制,所以你随时可以发包,也随时可能收到包。

发送、接收函数都是异步非阻塞的,顷刻就能完成,所以收发交错进行着。也正因为如此,仅调用它们并不能保障发送或接收的完成。

例如发送函数Send,调用它可能有3种结果:错误、部分完成、全部完成。其中错误又分两种情况:一种是由各种网络问题导致的失败,你需要马上决定是放弃本次操作,还是启用某种对策;另一种是“忙”,你实际上不用马上理睬。你需要调用GetLastError来判断是哪种情况,GetLastError返回WSAEWOULDBLOCK,代表“忙”,为什么当你Send得

到WSAEWOULDBLOCK却不用理睬呢?因为CAsyncSocket会记得你的SendWSAEWOULDBLOCK了,待发送的数据会写入CAsyncSocket内部的发送缓冲区,并会在不忙的时候自动调用OnSend,发送内部缓冲区里的数据。同样,如果Send只完成了一部分,你也不需要理睬,尚未发送的数据同样会写入CAsyncSocket内部的发送缓冲区,并在不“忙”的时候自动调用OnSend完成发送。

与OnSend协助Send完成工作一样,OnRecieve、OnConnect、OnAccept也会分别协助Recieve、Connect、Accept完成工作。这一切都通过消息机制完成。

在你使用CAsyncSocket之前,必须调用AfxSocketInit初始化WinSock环境,而AfxSocketInit会创建一个隐藏的CSocketWnd对象,由于这个对象由Cwnd派生,因此它能够接收Windows消息。一方面它会接受各个CAsyncSocket的状态报告,另一方面它能捕捉系统发出的各种SOCKET事件。所以它能够成为高层CAsyncSocket对象与WinSock底层之间的桥梁:例如某CAsyncSocket在Send时WSAEWOULDBLOCK了,它就会发送一条消息给CSocketWnd作为报告,CSocketWnd会维护一个报告登记表,当它收到底层WinSock发出的空闲消息时,就会检索报告登记表,然后直接调用报告者的OnSend函数。所以前文所说的CAsyncSocket会自动调用OnXxx,实际上是不对的,真正的调用者是CSocketWnd——它是一个CWnd对象,运行在独立的线程中。

四、 网络事件处理流程

在理解了上面的机制后, 让我们了解下CAsyncSocket的通信流程;

Void CMyAsyncSocket::OnReceive(int nErrorCode)

或则 调用父类的OnReceive()

Void CMyAsyncSocket::OnReceive( int nErrorCode)

六、 为何服务器Socket不监听

在创建服务器Socket的时候,只有采用SOCK_STREAM(字符流),Listen才能成功;

采用SOCK_DGRAM(数据报文)创建的Socket是面向无连接发式(UDP),所以Listen不成功(有待验证)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: