MFC之CAsyncSocket详解

CAsyncSocket类是从Object类派生而来。CAsyncSocket对象称为异步套接字对象

使用CAsyncSocket进行网络编程,可以充分利用Windows操作系统提供的消息驱动机制,通过应用程序框架来传递消息,方便地处理各种网络事件。另一方面,作为MFC微软基础类库中的一员,CAsyncSocket可以和MFC的其他类融为一体,大大扩展了网络编程的空间,方便了编程。

 

使用CAsyncSocket的一般步骤

网络应用程序一般采用客户端/服务器模式,他们使用的CAsyncSocket编程有所不同,下面以表格的形式方式看一下服务器和客户端之间的不同

 

序号服务端客户端
1

构造一个套接字

CAsyncSocket sockServer

构造一个套接字

CAsyncSocket sockClient

2

创建SOCKET句柄,绑定到指定的端口

sockServer.Create(nPort);

创建SOCKET句柄,使用默认参数

sockClient.Create();

3

启动监听,时刻准备接收连接请求

sockServer.Listen();

 
4 

请求链接服务器

sockClient.Connect(strAddress,nPort)

5

构造一个新的空套接字

CAsyncSocket sockRecv;

接收连接

sockServer.Accept(sockRecv);

 
6

接收数据

sockRecv.Receive(pBuffer,nLen);

发送连接

sockClient.Send(pBuffer,nLen);

7

发送数据

sockRecv.Send(pBuffer,nLen);

接收数据

sockClient.Receive(pBuffer,nLen);

8

关闭套接字对象

sockRecv.Close();

关闭套接字对象

sockClient.Close();

ps:客户端与服务端都要首先构造一个CAsyncSocket对象,然后使用该对象的Create成员函数来创建底层的SOCKET句柄。服务器端要绑定到特定的端口

 

对于服务器端的套接字对象,应使用CAsyncSocket::Listen函数进行监听状态,一旦收到来自客户端的链接请求,就调用CAsyncSocket::Accept来接收。对于客户端的套接字对象,应当使用CAsyncSocket::Connect来连接到一个服务器端的套接字对象。建立链接之后,双方就可以按照应用层协议交换数据了。

这里需要注意,Accept是将一个新的空CAsyncSocket对象作为它的参数,在调用Accept之前必须构造这个对象。与客户端套接字的连接是通过它建立的,如果这个套接字对象退出,连接也就关闭。对于这个新的套接字对象,不需要调用Create来创建它的底层套接字

 

调用CAsyncSocket对象的其他成员函数,如Send和Receive执行与其他套接字对象的通信,这些成员函数与Windows Sockets API函数在形式和用法上基本是一致的。

 

关闭并销毁CAsyncSocket对象。如果在堆栈上创建了套接字对象,当包含此对象的函数退出时,会调用该类的析构函数,销毁该对象。在销毁该对象之前,析构函数会调用该对象的Close成员函数。如果在堆上使用new创建了套接字对象,可先调用Close成员函数关闭它,在使用delete来删除释放该对象

 

在使用CAsyncSocket进行网络通信时,我们还需要处理以下几个问题:

 

1.堵塞处理,CAsyncSocket对象专用于异步操作,不支持堵塞工作模式,如果应用程序需要支持堵塞操作,必须自己解决

2.字节顺序的转换。在不同的结构类型的计算机之间进行数据传输时,可能会有计算机之间字节存储顺序不一致的情况。用户程序需要自己对不用的字节顺序进行转换

3.字符串转换。同样,不同结构类型的计算机的字符串存储顺序也可能不同,需要自行转换,如Unicode和ANSI字符串之间的转换

 

创建CAsyncSocket对象

创建异步套接字对象一般是分为两个步骤,首先要构造CAsyncSocket对象,其次创建该对象底层的SOCKET句柄

 

1.创建空的CAsyncSocket对象

通过调用CAsyncSocket构造函数,创建一个新的空CAsyncSocket套接字对象,构造函数还带参数。套接字对象创建之后必须调用他的成员函数来创建底层的套接字数据结构,并绑定他的地址

 

方法如下:

1.

C++

 
  1. CAsyncSocket Sock

  2. Sock.Create(...)

2.

C++

 
  1. CAsyncSocket *pSock = new CAsyncSocket;

  2. pSock->Create(...);

  3.  
  4. delete pSock;

  5. pSock =NULL;

ps:之前见过很多朋友释放指针的时候总是delete就完事了,往往不知正在给自己的程序带来前所未有的灾难,而此时的指针我们称之为“野指针”,注意:野指针不是NULL指针,而是不可用内存的指针,即垃圾指针;野指针是很危险的,因为我们无法通过if去判断指针是正常指针还是野指针,所以,我们在书写代码时一定要养成良好的编程习惯!!!避免野指针的方法我们可以通过以下几点:

1.声明指针一定要初始化,如果不初始化为NULL,那么此时一定要指向一块合法的内存

2.当调用delete或者free去释放指针后,一定要将指针重新指向NULL,可以参照SkinUI的SafeDelete

3.指针操作超出了变量的作用范围,比如如下代码,

C++

 
  1. class A

  2. {

  3. void Fun(){}

  4. };

  5. class B

  6. {

  7. A *m_A;

  8. B(){m_A=NULL;}

  9.  
  10. void Fun()

  11. {

  12. A a

  13. m_A =&a;

  14. //注意变量A的生命周期,当该方法执行完毕后,A会被释放,此时m_A就变成了无效的野指针

  15. }

  16. void Fun1()

  17. {

  18. m_A->Fun(); //m_A为野指针,到这里也就出现了错误

  19. }

  20. };

通过上述方法可以大大的降低代码出现野指针的风险。

 

2.创建CAsyncSocket套接字的底层套接字句柄

通过CAsyncSocket::Create创建该对象的底层套接字句柄,决定套接字对象的具体特性。

函数原型如下:

C++

 
  1. BOOL Create(

  2. UINT nSocketPort = 0,

  3. int nSocketType = SOCK_STREAM,

  4. long lEvent = FD_READ|FD_WRITE|FD_OOB|FD_ACCEPT|FD_CONNECT|FD_CLOSE,

  5. LPCTSTR lpszSocketAddress = NULL

  6. );

 

参数:

nSocketPort,指定了一个分配给套接字的传输层端口号,默认值为0,表示让系统为这个套接字分配一个自由的端口号。但是对于服务器应用程序而言,一般都需要事先分配一个公认的端口号,所以切记,服务器应用程序调用此函数时,必须分配一个端口号

nSocketType,套接字的类型,当指定为SOCK_STREAM时表示生成流式套接字,若使用SOCK_DGRAM表示生成数据报套接字

lEvent,指定为CAsyncSocket对象生成通知消息的套接字事件,默认对所有的套接字事件都生成通知消息

lpszSocketAddress,指定套接字的网络地址,对Internet通信域来说,就是主机的域名或者ip地址,比如www.gymsaga.com或123.123.123.123。如果使用默认值,表示使用默认的本机ip地址

 

关于CAsyncSocket可以接受并处理的消息事件

在CAsyncSocket::Create中,参数lEvent指定了为CAsyncSocket对象生成通知消息的套接字事件,最能体现CAsyncSocket对Windows消息驱动机制的支持

先认识一下这六种相关事件和通知消息

关于lEvent参数的符号常量,我们可以在WinSock中找到

C++

 
  1. /*

  2. * Define flags to be used with the WSAAsyncSelect() call.

  3. */

  4. #define FD_READ 0x01

  5. #define FD_WRITE 0x02

  6. #define FD_OOB 0x04

  7. #define FD_ACCEPT 0x08

  8. #define FD_CONNECT 0x10

  9. #define FD_CLOSE 0x20

它们代表了MFC套接字对象可以接收并处理的6种网络事件,当事件发生时,套接字对象会收到相应的通知消息,并自动执行套接字对象响应的事件处理函数

1:FD_READ :   通知有数据可读。当一个套接字对象的数据输入缓冲区收到其他套接字对象发送来的数据时,发生此事件,并通过该套接字对象 ,告诉它可以调用Receive成员来接收数据

2:FD_WRITE:   通知可以写数据,当一个套接字对象的数据输出缓冲区中的数据已经发送出去,输出缓冲区已腾空时,发生此事件,并通过该套接字对象,告诉它可以调用Send函数向外发送数据

3:FD_ACCEPT:  通知监听套接字有连接请求可以接收。当客户端的链接请求到达服务器时,进一步说,是当客户端的连接请求已经进入服务器监听套接字的接收缓冲区队列时,发生此事件,并通过监听套接字对象,告诉它可以调用Accept成员来接收待决的链接请求。这个事件仅对流式套接字有效,并且发生在服务器端

4:FD_CONNECT: 通知请求链接的套接字,链接的要求已经被处理。当客户端的连接请求已被处理时,发生此事件。存在两种情况:一种是服务器端已接收了链接请求,双方的连接已经建立,通知客户端套接字,可以使用链接来传输数据了;另一种情况是链接请求被拒绝,通知客户机套接字,它所请求的连接失败。这个事件仅对流式套接字有效,并且发生在客户端

5:FD_CLOSE:   通知套接字已关闭。当链接的套接字关闭时发生

6:FD_OOB:     通知将带外数据到达。当对方的流失套接字发送带外数据时,发生此事件,并通知接收套接字,正在发送的套接字有带外数据要求发送,带外数据是有没对链接的流失套接字相关的在逻辑上独立的通道,带外数据通道典型的是用来发送紧急数据。MFC支持带外有数据,使用CAsyncSocket类的高级用户可能需要使用带外数据通道,但不鼓励使用CSocket类的用户使用它,更容易的方法是创建第二个套接字来传送这样的数据

 

MFC框架对这六种事件的处理

当上述的网络事件发生时,MFC框架做何处理呢?MFC框架按照Windows系统的消息驱动把消息发送给相应的套接字对象,并调用作为该对象函数的事件处理函数,事件与处理函数一一映射。

 

在afxSock.h中我们可以找到CAsyncSocket类对这六种对应事件的处理函数

C++

 
  1. // Overridable callbacks

  2. protected:

  3. virtual void OnReceive(int nErrorCode);

  4. virtual void OnSend(int nErrorCode);

  5. virtual void OnOutOfBandData(int nErrorCode);

  6. virtual void OnAccept(int nErrorCode);

  7. virtual void OnConnect(int nErrorCode);

  8. virtual void OnClose(int nErrorCode);

其中参数nErrorCode的值,是在函数被调用时,由MFC框架提供的,表明套接字最新的状况,如果是0,说明成功,如果为非零值,说明套接字对象有某种错误

当某个网络事件发生时,MFC框架会自动调用套接字对象对应的事件处理函数。这就相当于给套接字对象一个通知,告诉它某个重要的事件已经发生,所以也称为套接字类的通知函数或者回调函数

 

3.重载套接字对象的回调函数

在编程中,一般我们不会直接去使用CAsyncSocket或者CSocket,而是从他们派生出自己的套接字类来。然后在派生类中对这些虚函数进行重载处理,加入应用程序对于网络事件处理的特定代码

如果是从CAsyncSocket类派生了自己的套接字类,就必须重载该应用程序所感兴趣的那些网络事件所对应的通知函数。如果从CSocket类派生一个类,是否重载所感兴趣的通知函数则由自己决定。也可以使用CSocket类本身的回调函数,但默认情况下,CSocket本身的回调函数什么也不做,只是一个空函数。

MFC框架自动调用通知函数,使得用户可以在套接字被通知的时候来优化套接字的行为。例如,用户可以从自己的OnReceive通知函数中调用套接字对象的成员函数Receive,就是说,在被通知的时候,已经有数据可读了,才调用Receive来读取它。这个方法不是必须的,但它是一个有效的方案。此外,也可以使用自己的通知函数跟踪进程,打印TRACE消息等

对于CSocket对象,还有如下一些不同之处

在一个诸如接收或者发送数据的操作期间,一个CSocket对象成为同步的,在同步状态期间,在当前套接字等待它想要的通知时,任何的为其他套接字的通知被排成队列,一旦该套接字完成了它的同步操作,并再次成为异步的,其他的套接字才可以开始接收排列的通知

 

重要的一点是:在CSocket中,从来不调用OnConncet通知函数,对于连接,简单的调用Conncet函数,仅当连接完成时,无论成功还是失败,该函数都返回,连接通知如何被处理是一个MFC内部的实现细节。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/432305.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

codevs1040 统计单词个数

题目描述 Description给出一个长度不超过200的由小写英文字母组成的字母串(约定;该字串以每行20个字母的方式输入&#xff0c;且保证每行一定为20个)。要求将此字母串分成k份(1<k<40)&#xff0c;且每份中包含的单词个数加起来总数最大(每份中包含的单词可以部分重叠。当…

UE MATH

1. 求两点的单位向量

root 密码丢失后的重新设置

/usr/local/mysql/bin/mysqld_safe --skip-grant-tables & mysql> use mysql; mysql> update user set passwordPASSWORD("root") where userroot;service mysqld stop; service mysqld start;/usr/local/mysql/bin/mysql -u root -p 转载于:https://w…

yum安装git

此方法对于RHEL、Fedora、CentOS有效&#xff1a; 1.yum install git 2.yum istall git-svn git-email git-gui gitk 转载于:https://www.cnblogs.com/moqiang02/p/4061129.html

材质

1. 随摄像机变化的镜面放射效果 2. 给物体表面增加抛光度 3. 菲涅耳透镜效果

Metasploit Framework命令汇总

一、msfconsole ? 帮助菜单back 从当前环境返回banner 显示一个MSF bannercd 切换目录color 颜色转换connect 连接一个主机exit 退出MSFhelp 帮助菜单info 显示一个或多个模块的信息irb 进入irb脚本模式jobs 显示和管理作业kill 杀死一个作业load 加载一个插件loadpath 在一个…

html keyup事件,jquery keyup事件为什么不执行?

先指出你的一个错误点$(#skillKey).on(click, tr, function () {$(this).css(color,red);$(this).keyup(function(){alert(123)});});你这样绑定事件&#xff0c;结果是点击一次tr绑定一次&#xff0c;点了多少次就绑定了多少次&#xff0c;这个例子还是不明显&#xff0c;你在…

cable

1. 建立一个actor&#xff0c;添加一个cable, 然后添加两个mesh作为cable的两个端点 2. 在编辑器中只能设置cable终点attach的mesh和mesh的socket, 因此需要在actor的构成函数里手动的设置 cable起点attach的mesh和socket

windows下memcache的安装总结

一、memcache软件的安装&#xff1a; 1、下载memcache的windows版本&#xff0c;把memcached.exe放在F:盘符&#xff0c;&#xff08;memcached.exe文件位置不可变动&#xff09;。 2、进入cmd命令终端&#xff0c;进入到F:盘符。 3、memcached.exe -d install 命令进行memcach…

html 调用c#dll中的控件,C#调用ActiveX控件的方法

C#调用ActiveX控件时通常要进行两步操作&#xff1a;第一步&#xff1a;注册控件&#xff0c;例如ABE.DLL&#xff0c;将ABE.DLL拷贝至系统文件夹SYSTEM32下&#xff0c;然后在开始中执行CMD命令&#xff0c;regsvr32 ABE.DLL&#xff0c;会提示注册成功&#xff1b;第二步&…

Android-将切换tabs的指示器合并到ActionBar上

最近比较忙&#xff0c;好久没更新过博客。国庆第一天没回家&#xff0c;闲下来可以把之前就想贴上来的东西写一下。 使用过Smooth和Fuubo这两个优秀的第三方微博客户端的同学应该见过他们的主页UI&#xff0c;如下图&#xff1a; 他们把切换tabs的指示器放在了ActionBar上&…

html5教学文档笔记,4.HTML 教程- (HTML5 基础)

HTML 教程- (HTML5 基础)1.HTML 标题HTML 标题(Heading)是通过- 标签来定义的.2.HTML 段落HTML 段落是通过标签 来定义的.3.HTML 链接HTML 链接是通过标签 来定义的.提示:在 href 属性中指定链接的地址。菜鸟教程(runoob.com)这是一个链接使用了 href 属性这是一个链接使用了 …

虚幻4渲染系统结构解析

本文根据小米互娱 VR 技术专家 房燕良在 MDCC 2016 移动开发者大会上的演讲整理而成&#xff0c;PPT 下载地址&#xff1a;http://download.csdn.net/detail/sinat_14921509/9639244。 小米互娱 VR 技术专家 房燕良 房燕良&#xff0c;从 2001 年开始&#xff0c;自主研发 3 代…

J2EE应用与移动互联网-写在前头

通过面向移动互联网的内容管理系统开发实践&#xff0c;积攒了一些J2EE应用和前端应用的知识&#xff0c;列出目录以供后期补充成册。 1.EJB的理解 1.1 EJB组件 1.2 数据库连接池 1.3 POJO 1.4 任务 1.5 容器 2.Spring生态 2.1 Spring Ioc 2.2 Spring AOP 2.3 Spring MVC 2.4 S…

【Modern OpenGL】前言

说明&#xff1a;跟着learnopengl的内容学习&#xff0c;不是纯翻译&#xff0c;只是自己整理记录。 强烈推荐原文&#xff0c;无论是内容还是排版。 原文链接 本文地址: http://blog.csdn.net/aganlengzi/article/details/50354140 欢迎来到OpenGL 欢迎来到OpenGL学习之旅&…

对象指针

向对象程序设计上机练习九&#xff08;对象指针&#xff09; Time Limit: 1000MS Memory limit: 65536K 题目描述 建立对象数组&#xff0c;内放5个学生数据&#xff08;学号是字符串类型、成绩是整型&#xff09;&#xff0c;设立max函数&#xff0c;用指向对象的指针作函数参…

如何利用计算机实现非线性转换,2013《数字信号处理》期末复习(填空选择判断)真题解析...

一、填空、选择、判断&#xff1a;1. 一线性时不变系统&#xff0c;输入为 x (n )时&#xff0c;输出为y (n ) &#xff1b;则输入为2x (n )时&#xff0c;输出为 2y(n) &#xff1b;输入为x (n-3)时&#xff0c;输出为 y(n-3) 。2. 线性时不变系统离散时间因果系统的系统函数为…

Windows FFMPEG开发环境配置

1.去FFMPEG网站上下载Dev版本的库&#xff0c;里面有我们需要的头文件和lib文件&#xff0c;然后下载Shared版本的库&#xff0c;里面有我们需要的dll文件 http://ffmpeg.zeranoe.com/builds/ 记得区分32位和64位的库&#xff0c;这里碰到一个大坑&#xff0c;就是我下载的是6…

Ant命令行操作

Ant命令行操作 Ant构建文件可以将项目编译&#xff0c;打包&#xff0c;測试&#xff0c;它是Apache软件基金会jakarta文件夹中的一个子项目&#xff0c;具有跨平台性&#xff0c;操作简单&#xff0c;并且非常easy上手。 关于Ant执行&#xff0c;能够在项目中找到build.xml直接…