继续话题——软件中的异步非阻塞通讯方式。

由于软件基于MFC开发,所以实现异步通讯时使用了CAsyncSocket类。

首先要了解CAsyncSocket异步机制,引用自

http://blog.csdn.net/tianhai110/article/details/2115270

由于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的原理,而具体代码如下(接收端):

首先在头文件中声明继承自CAsyncSocket的类,并重写三个方法:

#include <afxsock.h>

class CMyAsyncSocket :
public CAsyncSocket
{
public:
CMyAsyncSocket(void);
~CMyAsyncSocket(void); virtual void OnClose(int nErrorCode);
virtual void OnConnect(int nErrorCode);
virtual void OnReceive(int nErrorCode);
};

在cpp文件中分别实现这三个方法:

void CMyAsyncSocket::OnClose(int nErrorCode)
{
if ( == nErrorCode)
{
Close();
}
CAsyncSocket::OnClose(nErrorCode);
} void CMyAsyncSocket::OnConnect(int nErrorCode)
{
if ( == nErrorCode)
{
//TODO:建立连接后的动作
}
CAsyncSocket::OnConnect(nErrorCode);
} void CMyAsyncSocket::OnReceive(int nErrorCode)
{
if ( == nErrorCode)
{
//TODO:接受后的处理
        char szRcv[513] = "";
        int nRcved = Receive(szRcv,15);
}
CAsyncSocket::OnReceive(nErrorCode);
}

接下来,在需要通信的文件中就可以调用这个类:

    CMyAsyncSocket m_pClientSocket; 

    AfxSocketInit();
m_pClientSocket.Create();
m_pClientSocket.Connect(_T("IP"),PORT);

在使用过程中有三个地方需要注意:

    1.使用前进行AfxSocketInit()初始化;

2.如果出现消息只能接受一次的现象,注意在Receive()后调用父类的OnReceive();

3.在一个方法中,Connect()函数后面不能出现其他代码(这个尚不清楚原因)。

C++ 非阻塞套接字的使用 (2)的更多相关文章

  1. C++ 非阻塞套接字的使用 (3)

    异步非阻塞套接字避免了死循环的接收问题,但是软件用起来体验还是很差.究其原因,软件在指令的发送.接收上, 采取了一种不合理的方式:在指令的发送后,立刻调用接收函数,等待回令. 若是采用同步阻塞套接字, ...

  2. python_非阻塞套接字及I/O流

    http://www.cnblogs.com/lixy-88428977/p/9638949.html 首先,我们要明确2个问题: 普通套接字实现的服务端有什么缺陷吗? 有,一次只能服务一个客户端! ...

  3. 非阻塞套接字编程, IO多路复用(epoll)

    非阻塞套接字编程: server端 import socket server = socket.socket() server.setblocking(False) server.bind(('', ...

  4. 非阻塞套接字与IO多路复用

    我们了解了socket之后已经知道,普通套接字实现的服务端的缺陷:一次只能服务一个客户端! 并且,为了使一个客户端能够不断收发消息,我们还要使用while循环来轮询,这极大地降低了我们的效率 acce ...

  5. 11 非阻塞套接字与IO多路复用(进阶)

    1.非阻塞套接字 第一部分 基本IO模型 1.普通套接字实现的服务端的缺陷 一次只能服务一个客户端! 2.普通套接字实现的服务端的瓶颈!!! accept阻塞! 在没有新的套接字来之前,不能处理已经建 ...

  6. 非阻塞套接字与IO多路复用(转,python实现版)

    非阻塞:指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回.epoll工作在非阻塞模式时,才会发挥作用. 我们了解了socket之后已经知道,普通套接字实现的服务端的缺陷:一次只能服务一个 ...

  7. C++ 非阻塞套接字的使用 (1)

    在维护代码的过程中,发现软件运行的CPU占用率居高不下,在4核的电脑上占用了25%的CPU.查阅资料的得知,这是可能是由于软件中出现了死循环. 经过对软件的一些测试,最终确定了死循环出现的位置——通讯 ...

  8. 阻塞套接字返回EAGAIN

    今天用NDK写了一个通信程序,发现阻塞SOKCET 读写的时候返回了EAGAIN.NDK下PERROR输出为Try Again.查了半天头文件 在网上找到了原因.在此纪录.网址为http://blog ...

  9. 非阻塞SOCKET套接字connect等待时间的实现

     SOCKET cClient;     cClient=socket(AF_INET,SOCK_STREAM,0);     //设置为非阻塞套接字     int iMode = 1;     i ...

随机推荐

  1. SQL 查询性能优化----解决书签查找

    先来看看什么是书签查找: 当优化器所选择的非聚簇索引只包含查询请求的一部分字段时,就需要一个查找(lookup)来检索其他字段来满足请求.对一个有聚簇索引的表来说是一个键查找(key lookup), ...

  2. js获取get方式传递的参数

    String.prototype.GetValue= function(parm) { var reg = new RegExp("(^|&)"+ parm +" ...

  3. js闭包使用

    闭包就是在一个函数内定义一个内部函数 并返回内部函数 function f1(){ var a=1; add=function(){a=a+1;} function f1Sub(){ console. ...

  4. Python模块:itertools

    itertools模块:循环器 一,无穷循环器:count,cycle,repeat (1)count(5,3) #从5开始的整数循环器,每次增加3,即:5,8,11,14,17... from it ...

  5. Python编写邮件群发(qq邮箱)

    #电子邮件操作 import poplib import smtplib from email.header import decode_header from email.mime.text imp ...

  6. JavaScript基础知识整理(2)

    15.处理图像 注意:(1)在写js文件时,尽量将函数的声明往后写,将函数调用写在前面,这样能够使代码结构很清晰. (2)一个网页中翻转器一般超过3个,所以使用for循环减少重复使用翻转器代码的次数. ...

  7. Javascript.ReactNative-2-javascript-syntax-in-react-native

    JavaScript Syntax in React Native Contents: Arrow Function Let+Const Default + Rest + Spread Destruc ...

  8. Xcode7以后 使用空模板

    Xcode7以后的版本没有空模板可以选择 习惯使用空模版的 可以自己拷贝空模版文件夹 放到模版的位置 重启就可以使用了 1:首先 需要有一个空模版 没有空模板的可以在下面路径下下载一个 并解压 htt ...

  9. 十分钟使用github pages +hexo拥有个人博客

    最近想自己搭建自己的个人博客,毕竟这样觉得比较geek,但是搜了资料,感觉良莠不齐,好多东西说的含糊不清,于是自己记录下自己的搭建过程. 1, 安装nodejs 2, 安装git 3, 申请githu ...

  10. Hibernate缓存之Aop+cache

    在上一篇涉及到查询缓存的功能时除了需要在配置文件中开启缓存外,还需要在业务代码中显示调用setCacheable(boolean)才可以打开查询缓存的功能,这样做,无疑是破坏了封装性,所以就诞生了利用 ...