MFC网络编程-

上传人:hjk****65 文档编号:178019903 上传时间:2022-12-27 格式:DOC 页数:63 大小:356KB
收藏 版权申诉 举报 下载
MFC网络编程-_第1页
第1页 / 共63页
MFC网络编程-_第2页
第2页 / 共63页
MFC网络编程-_第3页
第3页 / 共63页
资源描述:

《MFC网络编程-》由会员分享,可在线阅读,更多相关《MFC网络编程-(63页珍藏版)》请在装配图网上搜索。

1、网络程序设计教材一、TCP/IP体系结构、特点及相关术语1、TCP/IP体系结构TCP/IP协议实际上就是在物理网上的一组完整的网络协议。其中TCP是提供传输层服务,而IP则是提供网络层服务。TCP/IP包括以下协议:(结构如图1.1)IP: 网间协议(Internet Protocol) 负责主机间数据的路由和网络上数据的存储。同时为ICMP,TCP,UDP提供分组发送服务。用户进程通常不需要涉及这一层。ARP: 地址解析协议(Address Resolution Protocol)此协议将网络地址映射到硬件地址。RARP: 反向地址解析协议(Reverse Address Resoluti

2、on Protocol)此协议将硬件地址映射到网络地址ICMP: 网间报文控制协议(Internet Control Message Protocol)此协议处理信关和主机的差错和传送控制。TCP: 传送控制协议(Transmission Control Protocol)这是一种提供给用户进程的可靠的全双工字节流面向连接的协议。它要为用户进程提供虚电路服务,并为数据可靠传输建立检查。(注:大多数网络用户程序使用TCP)UDP: 用户数据报协议(User Datagram Protocol)这是提供给用户进程的无连接协议,用于传送数据而不执行正确性检查。FTP: 文件传输协议(File Tra

3、nsfer Protocol)允许用户以文件操作的方式(文件的增、删、改、查、传送等)与另一主机相互通信。SMTP: 简单邮件传送协议(Simple Mail Transfer Protocol)SMTP协议为系统之间传送电子邮件。TELNET:终端协议(Telnet Terminal Procotol)允许用户以虚终端方式访问远程主机HTTP: 超文本传输协议(Hypertext Transfer Procotol)TFTP: 简单文件传输协议(Trivial File Transfer Protocol)2、IP地址和子网掩码 要学习TCP/IP协议,首先要提到的是IP地址。每台主机的IP

4、地址是一个32位的二进制数。每个IP地址被分割位两部分:前缀和后缀。前缀用来确定计算机从属的物理网络,后缀用来确定网络上单独的计算机。互联网上每一个物理网络都有一个唯一的值作为网络号,该网络号必须全球一致。1、IP地址分类:IP地址分位五类:A类、B类、C类、D类、E类其中A类、B类和C类为基本类D类用于多播E类属于保留类,现在不用。它们的格式如下(其中*代表网络号): A类:0* XXXXXXXX XXXXXXXX XXXXXXXX B类:10* * XXXXXXXX XXXXXXXX C类:110* * * XXXXXXXX D类:1110* XXXXXXXX XXXXXXXX XXXXX

5、XXX E类:1111* XXXXXXXX XXXXXXXX XXXXXXXX 这样,A类地址的范围为:0.0.0.0-127.255.255.255 B类地址的范围为:128.0.0.0-191.255.255.255 C类地址的范围为:192.0.0.0-223.255.255.255 D类地址的范围为:224.0.0.0-239.255.255.255 E类地址的范围为:240.0.0.0-247.255.255.266 几个特殊IP地址 网络地址:IP地址中主机地址全为0的地址,如128.211.0.0。 广播地址:IP地址中主机地址全为1的地址,如128.211.255.255。 环

6、回地址:127.0.0.1,主要用于测试。2、子网掩码: 现在的主机都要求支持子网掩码,不再把IP地址看成为由单纯的一个网络号和一个主机号组成,而是把主机号再分成一个子网号和一个主机号。例如一个B类地址(140.252),在剩下的16位中,8位用于子网号,8位用于主机号,这样就允许254个子网,每个子网就可以有254台主机。为了确定多少位用于子网号,多少位用于主机号,这就要用到子网掩码了。其中值为1的位留给网络号和子网号,为0的位留给主机号。3、TCP/IP特点TCP/IP协议的核心部分是传输层协议(TCP、UDP),网络层协议(IP)和物理接口层,这三层通常是在操作系统内核中实现。因此用户一

7、般不涉及。编程时,编程界面有两种形式:一、是由内核心直接提供的系统调用;二、使用以库函数方式提供的各种函数。前者为核内实现,后者为核外实现。用户服务要通过核外的应用程序才能实现,所以要使用套接字(socket)来实现。图1.2是TCP/IP协议核心与应用程序关系图。二、专用术语1、套接字它是网络的基本构件。它是可以被命名和寻址的通信端点,使用中的每一个套接字都有其类型和一个与之相连听进程。套接字存在通信区域(通信区域又称地址簇)中。套接字只与同一区域中的套接字交换数据(跨区域时,需要执行某和转换进程才能实现)。WINDOWS 中的套接字只支持一个域网际域。套接字具有类型。WINDOWS SOC

8、KET 1.1 版本支持两种套接字:流套接字(SOCK_STREAM)和数据报套接字(SOCK_DGRAM) 2、WINDOWS SOCKETS 实现一个WINDOWS SOCKETS 实现是指实现了WINDOWS SOCKETS规范所描述的全部功能的一套软件。一般通过DLL文件来实现3、阻塞处理例程阻塞处理例程(blocking hook,阻塞钩子)是WINDOWS SOCKETS实现为了支持阻塞套接字函数调用而提供的一种机制。4、多址广播(multicast,多点传送或组播)是一种一对多的传输方式,传输发起者通过一次传输就将信息传送到一组接收者,与单点传送(unicast)和广播(Broa

9、dcast)相对应。1、客户机/服务器模式在TCP/IP网络中两个进程间的相互作用的主机模式是客户机/服务器模式(Client/Server model)。该模式的建立基于以下两点:1) 非对等作用;2) 通信完全是异步的。客户机/服务器模式在操作过程中采取的是主动请示方式:首先服务器方要先启动,并根据请示提供相应服务:(过程如下)1、打开一通信通道并告知本地主机,它愿意在某一个公认地址上接收客户请求。2、等待客户请求到达该端口。3、接收到重复服务请求,处理该请求并发送应答信号。4、返回第二步,等待另一客户请求5、关闭服务器。客户方:1、打开一通信通道,并连接到服务器所在主机的特定端口。2、向

10、服务器发送服务请求报文,等待并接收应答;继续提出请求3、请求结束后关闭通信通道并终止。2、基本套接字为了更好说明套接字编程原理,给出几个基本的套接字,在以后的篇幅中会给出更详细的使用说明。1、创建套接字socket()功能:使用前创建一个新的套接字格式:SOCKET PASCAL FAR socket(int af,int type,int procotol);参数:af: 通信发生的区域type: 要建立的套接字类型procotol: 使用的特定协议2、指定本地地址bind()功能:将套接字地址与所创建的套接字号联系起来。格式:int PASCAL FAR bind(SOCKET s,con

11、st struct sockaddr FAR * name,int namelen);参数:s: 是由socket()调用返回的并且未作连接的套接字描述符(套接字号)。其它:没有错误,bind()返回0,否则SOCKET_ERROR地址结构说明:struct sockaddr_inshort sin_family;/AF_INETu_short sin_port;/16位端口号,网络字节顺序struct in_addr sin_addr;/32位IP地址,网络字节顺序char sin_zero8;/保留3、建立套接字连接connect()和accept()功能:共同完成连接工作格式:int P

12、ASCAL FAR connect(SOCKET s,const struct sockaddr FAR * name,int namelen);SOCKET PASCAL FAR accept(SOCKET s,struct sockaddr FAR * name,int FAR * addrlen);参数:同上4、监听连接listen()功能:用于面向连接服务器,表明它愿意接收连接。格式:int PASCAL FAR listen(SOCKET s, int backlog);5、数据传输send()与recv()功能:数据的发送与接收格式:int PASCAL FAR send(SOCK

13、ET s,const char FAR * buf,int len,int flags);int PASCAL FAR recv(SOCKET s,const char FAR * buf,int len,int flags);参数:buf:指向存有传输数据的缓冲区的指针。 6、多路复用select()功能:用来检测一个或多个套接字状态。格式:int PASCAL FAR select(int nfds,fd_set FAR * readfds,fd_set FAR * writefds, fd_set FAR * exceptfds,const struct timeval FAR * ti

14、meout);参数:readfds:指向要做读检测的指针writefds:指向要做写检测的指针exceptfds:指向要检测是否出错的指针timeout:最大等待时间7、关闭套接字closesocket()功能:关闭套接字s格式:BOOL PASCAL FAR closesocket(SOCKET s);3、典型过程图2.1 面向连接的套接字的系统调用时序图2.2 无连接协议的套接字调用时序图面向连接的应用程序流程图对MFC封装 Windows 通讯 API的研究 一、 引 言 近 年 来, 利 用Internet 进 行 网 际 间 通 讯, 在WWW 浏 览、FTP、Gopher 这 些

15、常 规 服 务, 以 及 在 网 络 电 话、 多 媒 体 会 议 等 这 些 对 实 时 性 要 求 严 格 的 应 用 中 成 为 研 究 的 热 点, 而 且 已 经 是 必 需 的 了。Windows 环 境 下 进 行 通 讯 程 序 设 计 的 最 基 本 方 法 是 应 用Windows Sockets 实 现 进 程 间 的 通 讯, 为 此 微 软 提 供 了 大 量 基 于Windows Sockets 的 通 讯API, 如WinSock API、WinInet API 和ISAPI, 并 一 直 致 力 于 开 发 更 快、 更 容 易 的 通 讯API, 将 其 和M

16、FC 集 成 在 一 起 以 使 通 讯 编 程 越 来 越 容 易。 MFC 是VC 编 程 环 境 最 重 要 的 组 成 部 分, 它 为 用 户 提 供 了 一 大 批 预 先 定 义 的 类 和 成 员 函 数, 封 装 了 大 量 的Windows API。 同 时VC 环 境 提 供 了 与MFC 对 象 和 代 码 一 起 工 作 的 专 用 工 具:AppStudio 源 程 序 编 辑 器、AppWizard 和Class Wizard。 应 用 MFC, 可 以 使Windows 程 序 员 用 较 少 的 时 间 和 精 力 开 发 出 复 杂 的 通 讯 应 用 程

17、序。 本 文 根 据 笔 者 自 己 在 开 发 实 时 网 络 音 频 工 具FreeTalk 过 程 中 的 一 些 经 验, 介 绍Windows 环 境 下 的 常 用API 和 封 装 它 们 的MFC 类, 重 点 介 绍 使 用MFC 的CAsyncsocket 和CSocket 类 编 写 网 络 通 讯 程 序 的 方 法, 这 两 个 类 封 装 了WinSock API, 并 使 他 们 更 容 易 使 用 和 更 适 应 于MFC 编 程 环 境。 二、Windows 环 境 下 的 通 讯API 和 相 应 的MFC 类 1. Windows Sockets(WinS

18、ock)API- Windows Sockets 定 义 了Windows 的 网 络 编 程 接 口, 它 基 于 加 利 福 尼 亚 大 学 伯 克 利 分 校 的 伯 克 利Unix Sockets。Windows Sockets 既 包 括BSD 风 格 的 例 程, 还 加 入 了Windows 的 扩 展 部 分, 例 如 用 于 消 息 驱 动 的 扩 展 函 数。Windows Sockets 可 以 运 行 在 许 多 网 络 协 议 之 上, 包 括TCP/IP、XNS、DECNet、IPX/SPX 等。 在Win32 环 境 下,Windows Sockets 提 供 线

19、 程 安 全。 通 过 微 软 与 标 准 组 织 的 努 力, 为WinSock 定 义 了 应 用 程 序 设 计 接 口(WinSock API), 可 以 非 常 方 便 地 利 用 下 层 的 网 络 协 议( 如TCP/IP) 进 行 网 络 通 讯。 - 通 过 提 供 两 个 类CAsyncSocket 和CSocket,MFC 支 持 使 用WinSock API 通 讯 程 序 设 计。MFC 把 复 杂 的WinSock API 封 装 到 类 里, 这 使 得 编 写 应 用 程 序 更 容 易。CAsyncSocket 类 逐 个 封 装 了WinSock API,

20、为 高 级 网 络 程 序 员 提 供 了 更 加 有 力 而 灵 活 的 方 法。 这 个 类 基 于 程 序 员 了 解 网 络 通 讯 的 假 设, 目 的 是 为 了 在MFC 中 使 用WinSock, 程 序 员 有 责 任 处 理 诸 如 阻 塞、 字 节 顺 序 和 在Unicode 与MBCS 间 转 换 字 符 的 任 务。 为 了 给 程 序 员 提 供 更 方 便 的 接 口 以 自 动 处 理 这 些 任 务,MFC 给 出 了CSocket 类, 这 个 类 是 由CAsyncSocket 类 继 承 下 来 的, 它 提 供 了 比CAsyncSocket 更 高

21、 层 的WinSock API 接 口。Csocket 类 和CsocketFile 类 与Carchive 类 一 起 合 作 来 管 理 发 送 和 接 收 的 数 据, 这 使 管 理 数 据 收 发 更 加 便 利。CSocket 对 象 提 供 阻 塞 模 式, 这 对 于Carchive 的 同 步 操 作 是 至 关 重 要 的。 阻 塞 函 数 比 如Receive()、Send()、ReceiveFrom()、SendTo() 和Accept() 直 到 操 作 完 成 后 才 返 回 控 制 权, 因 此 如 果 需 要 低 层 控 制 和 高 效 率, 就 使 用Casy

22、ncSock 类; 如 果 需 要 方 便, 则 可 使 用Csocket 类。 2.Win32 Internet(WinInet)API - 微 软 公 布 了 一 些 使Internet 应 用 程 序 的 设 计 比 以 前 更 快、 更 容 易 的API:WinInet API, 它 提 供 了 中 高 层 通 信 函 数, 这 使 访 问 主 要 的Internet 协 议 变 得 相 当 容 易。 这 些 函 数 在 程 序 员 和WinSock 驱 动 之 间 提 供 了 隔 离 层。 有4 类WinInet API 函 数: 通 用WinInet 函 数、WinInet 文 件

23、 传 输 协 议(FTP) 函 数、WinInet Gopher 函 数、WinInet 超 文 本 传 输 协 议(HTTP) 函 数。 - 事 实 上,MFC 把WinInet API 和ActiveX 技 术 封 装 进 类, 使Internet 编 程 更 加 容 易, 这 些 类 包 括CInternetSession、CInternetConnection、CInternetFile、CHttpConnection、CHttpFile、CGopherFile、CFtpConnection、CGopherConnection、CFileFind、CFtpFileFind、CGophe

24、rFileFind、CGopherLocator 和CInternetException。 3.Internet 服 务 器API(ISAPI) - 微 软 的IIS 是 惟 一 与Windows NT Server 操 作 系 统 紧 密 集 成 的WWW 服 务 器, 它 作 为Internet/Intranet 服 务 器 应 用 范 围 很 广。IIS 允 许 扩 展 功 能, 这 是 通 过ISAPI 来 实 现 的,ISAPI 描 述 了 与Internet 服 务 器 之 间 的 接 口。 用ISAPI 提 供 的 工 具, 可 建 立 高 性 能、 高 效 率、 满 足 商 业

25、 安 全 及 符 合 新 的IIS 标 准 的Internet 服 务 器。 同 样,ISAPI 在MFC 中 由 典 型 的 类 所 封 装, 包 括CHttpFilter、CHttpFilterContext、CHttpServer、CHttpServerContext、Related Classes 和CHtmlStream。 三、WinSock API 的MFC 封 装 类 一 些 网 络 应 用 程 序( 如 网 络 电 话、 多 媒 体 会 议 工 具) 实 时 性 要 求 非 常 强, 要 求 能 够 直 接 应 用WinSock 发 送 和 接 收 数 据。 这 时 设 计 者

26、 应 该 选 择 直 接 应 用WinSock API 或 者 由MFC 封 装 的WinSock API。 新 开 发 的 应 用 程 序 中, 为 了 充 分 利 用MFC 的 优 势, 首 选 方 案 应 当 是MFC 中 的CAsyncSocket 类 和CSocket 类, 这 两 个 类 完 全 封 装 了WinSock API, 并 提 供 更 多 的 便 利。 本 文 介 绍 应 用 这 两 个 类 的 编 程 模 型, 并 引 出 相 关 的 成 员 函 数 与 一 些 概 念 的 解 释。 1.CAsyncSocket 类 和CSocket 类 简 述 附图 CAsyncS

27、ocket 类和 CSocket 类的继承关系 - CAsyncSocket 类 和CSocket 类 的 继 承 关 系 由 附 图 给 出。CSocket 类 是 由CAsyncSocket 继 承 而 来 的, 事 实 上, 在MFC 中CAsyncSocket 逐 个 封 装 了WinSock API, 每 个CAsyncSocket 对 象 代 表 一 个Windows Socket, 使 用CAsyncSocket 类 要 求 程 序 员 对 网 络 编 程 较 为 熟 悉。 相 比 起 来,CSocket 类 是CAsyncSocket 的 派 生 类, 继 承 了 它 封 装

28、的WinSock API。 一 个CSocket 对 象 代 表 了 一 个 比CAsyncSocket 对 象 更 高 层 次 的Windows Socket 抽 象,CSocket 类 与CSocketFile 类 和CArchive 类 一 起 工 作 来 发 送 和 接 收 数 据, 因 此 使 用 它 更 加 容 易。CSocket 对 象 提 供 阻 塞 模 式, 因 为 阻 塞 功 能 对 于CArchive 的 同 步 操 作 是 至 关 重 要 的。 在 这 里 有 必 要 对 阻 塞 的 概 念 作 一 解 释: 一 个socket 可 以 处 于“ 阻 塞 模 式” 或“

29、 非 阻 塞 模 式”, 当 一 个 套 接 字 处 于 阻 塞 模 式( 即 同 步 操 作) 时, 它 的 阻 塞 函 数 直 到 操 作 完 成 才 会 返 回 控 制 权, 之 所 以 称 为 阻 塞 是 因 为 此 套 接 字 的 阻 塞 函 数 在 完 成 操 作 返 回 之 前 什 么 也 不 能 做。 如 果 一 个socket 处 于 非 阻 塞 模 式( 即 异 步 操 作), 则 会 被 调 用 函 数 立 即 返 回。 在CAsyncSocket 类 中 可 以 用GetLastError 成 员 函 数 查 询 最 后 的 错 误, 如 果 错 误 是WSAEWOUL

30、DBLOCK 则 说 明 有 阻 塞, 而CSocket 绝 不 会 返 回WSAEWOULDBLOCK, 因 为 它 自 己 管 理 阻 塞。 微 软 建 议 尽 量 使 用 非 阻 塞 模 式, 通 过 网 络 事 件 的 发 生 而 通 知 应 用 程 序 进 行 相 应 的 处 理。 但 在CSocket 类 中, 为 了 利 用CArchive 处 理 通 讯 中 的 许 多 问 题 和 简 化 编 程, 它 的 一 些 成 员 函 数 总 是 具 有 阻 塞 性 质 的, 这 是 因 为CArchive 类 需 要 同 步 的 操 作。 在Win32 环 境 下, 如 果 要 使

31、用 具 有 阻 塞 性 质 的 套 接 字, 应 该 放 在 独 立 的 工 人 线 程 中 处 理, 利 用 多 线 程 的 方 法 使 阻 塞 不 至 于 干 扰 其 他 线 程, 也 不 会 把CPU 时 间 浪 费 在 阻 塞 上。 多 线 程 的 方 法 既 可 以 使 程 序 员 享 受CSocket 带 来 的 简 化 编 程 的 便 利, 也 不 会 影 响 用 户 界 面 对 用 户 的 反 应。 - 2.CAsyncsocket 类 编 程 模 型 - 在 一 个MFC 应 用 程 序 中, 要 想 轻 松 处 理 多 个 网 络 协 议, 而 又 不 牺 牲 灵 活 性

32、时, 可 以 考 虑 使 用CAsyncSocket 类, 它 的 效 率 比CSocket 类 要 高。CAsyncSocket 类 针 对 字 节 流 型 套 接 字 的 编 程 模 型 简 述 如 下: - (1) 构 造 一 个CAsyncSocket 对 象, 并 用 这 个 对 象 的Create 成 员 函 数 产 生 一 个Socket 句 柄。 可 以 按 如 下 两 种 方 法 构 造: CAsyncSocket sock;Sock.Create(); / 使 用 默 认 参 数 产 生 一 个 字 节 流 套 接 字 或CAsyncSocket*pSocket=new C

33、AsyncSocket;int nPort=27;pSocket-Create(nPort, SOCK-DGRAM);/ 指 定 端 口 号 产 生 一 个 数 据 报 套 接 字- 第 一 种 方 法 在 栈 上 产 生 一 个CAsyncSocket 对 象, 而 第 二 种 方 法 在 堆 上 产 生CAsyncSocket 对 象。 第 一 种Create 成 员 函 数 用 缺 省 参 数 产 生 一 个 字 节 流 套 接 字, 第 二 种Create 成 员 函 数 用 指 定 的 端 口 和 地 址 产 生 一 个 数 字 报 套 接 字。Create 的 参 数 有: - 端

34、 口,UINT 类 型。 注 意: 如 果 是 服 务 方, 则 使 用 一 个 众 所 周 知 的 端 口 供 服 务 方 连 接; 如 果 是 客 户 方, 典 型 做 法 是 接 受 默 认 参 数, 使 套 接 字 可 以 自 主 选 择 一 个 可 用 端 口; - socket 类 型。SOCK-STREAM( 默 认 值) 或SOCK-DGRAM; - socket 地 址。 例 如“” 或“202.193.64.33”。 - (2) 如 是 客 户 方 程 序, 用CAsyncSocket Connect 成 员 函 数 连 接 到 服 务 方; 如 是 服 务 方 程 序,

35、用CAsyncSocket Listen 成 员 函 数 开 始 监 听, 一 旦 收 到 连 接 请 求, 则 调 用CAsyncSocket Accept 成 员 函 数 开 始 接 收。 注 意:CAsyncSocket Accept 成 员 函 数 要 用 一 个 新 的 并 且 是 空 的CSocket 对 象 作 为 它 的 参 数, 这 里 所 说 的“ 空 的” 指 的 是 这 个 新 对 象 还 没 有 调 用Create 成 员 函 数。 - (3) 调 用 其 他 的CAsyncSocket 类 成 员 函 数 进 行 通 讯 管 理。 - (4) 通 讯 结 束 后,

36、销 毁CAsyncSocket 对 象。 如 果 是 在 栈 上 产 生 的CAsyncSocket 对 象, 则 对 象 超 出 定 义 的 范 围 时 自 动 被 析 构; 如 果 是 在 堆 上 产 生, 也 就 是 用 了new 这 个 操 作 符, 则 必 须 使 用delete 操 作 符 销 毁CAsyncSocket 对 象。 - 3.CSocket 类 编 程 模 型 - 使 用CSocket 对 象 涉 及CArchive 和CSocketFile 类 对 象。 以 下 介 绍 的 针 对 字 节 流 型 套 接 字 的 操 作 步 骤 中, 只 有 第3 步 对 于 客

37、户 方 和 服 务 方 操 作 是 不 同 的, 其 他 步 骤 都 相 同。 - (1) 构 造 一 个CSocket 对 象。 - (2) 使 用 这 个 对 象 的Create 成 员 函 数 产 生 一 个socket 句 柄。 在 客 户 方 程 序 中, 除 非 需 要 数 据 报 套 接 字,Create 一 般 情 况 下 应 该 使 用 默 认 参 数。 而 对 于 服 务 方 程 序, 必 须 在 调 用Create 时 指 定 一 个 端 口。 注 意:CArchive 不 能 与 数 据 报(UDP) 套 接 字 一 起 工 作, 因 此 对 于 数 据 报 套 接 字

38、,CAsyncSocket 和CSocket 的 使 用 方 法 是 一 样 的。 - (3) 如 果 是 客 户 方 套 接 字, 则 调 用CAsyncSocket Connect 与 服 务 方 套 接 字 连 接; 如 果 是 服 务 方 套 接 字, 则 调 用CAsyncSocket Listen 开 始 监 听 来 自 客 户 方 的 连 接 请 求, 收 到 连 接 请 求 后, 调 用CAsyncSocket Accept 接 受 请 求, 建 立 连 接。 注 意:Accept 成 员 函 数 需 要 一 个 新 的 并 且 为 空 的CSocket 对 象 作 为 它 的

39、 参 数, 解 释 同 上。 - (4) 产 生 一 个CSocketFile 对 象, 并 把 它 与CSocket 对 象 关 联 起 来。 - (5) 为 接 收 和 发 送 数 据 各 产 生 一 个CArchive 对 象, 把 它 们 与CSocketFile 对 象 关 联 起 来。 切 记CArchive 是 不 能 和 数 据 报 套 接 字 一 起 工 作 的。 - (6) 使 用CArchive 对 象 在 客 户 与 服 务 方 传 送 数 据。 (7) 通 讯 完 毕 后, 销 毁CArchive、CSocketFile 和CSocket 对 象。 三 使用MFC快速

40、实现网络编程 其实,VC+的MFC类库中提供了CAsyncSocket这样一个套接字类,用他来实现Socket编程,是非常方便的。 本文将用一个Echo例程来介绍CAsyncSocket类的用法。 一 客户端 1 创建一个Dialog Based项目:CSockClient。 2 设计对话框 去掉Ok和Cancle两个按钮,增加ID_Connect(连接)、ID_Send(发送)、ID_Exit(关闭)按钮,增加ListBox控件IDC_LISTMSG和Edit控件IDC_EDITMSG,并按下表在ClassWizard中为CCSockClientDlg类添加变量。 ControlIDType

41、MemberIDC_EDITMSGCEditm_MSGIDC_LISTMSClistBoxm_MSGS 3 CAsyncSocket类用DoCallBack函数处理MFC消息,当一个网络事件发生时,DoCallBack函数按网络事件类型:FD_READ、FD_WRITE、FD_ACCEPT、FD_CONNECT分别调用OnReceive、OnSend、OnAccept、OnConnect函数。由于MFC把这些事件处理函数定义为虚函数,所以要生成一个新的C+类,以重载这些函数,做法如下: 以Public方式继承CAsyncSocket类,生成新类MySock; 为MySock类添加虚函数OnRe

42、ceive、OnConnect、OnSend 4 在MySock.ccp中添加以下代码 #include CSockClient.h#include CSockClientDlg.h5 在MySock.h中添加以下代码 public: BOOL m_bConnected; /是否连接 UINT m_nLength; /消息长度 char m_szBuffer4096; /消息缓冲区6 在MySock.ccp中重载各函数 MySock:MySock()m_nLength=0;memset(m_szBuffer,0,sizeof(m_szBuffer);m_bConnected=FALSE;MyS

43、ock:MySock()/关闭套接字if(m_hSocket!=INVALID_SOCKET) Close();void MySock:OnReceive(int nErrorCode) m_nLength=Receive(m_szBuffer,sizeof(m_szBuffer),0);/下面两行代码用来获取对话框指针CCSockClientApp* pApp=(CCSockClientApp*)AfxGetApp();CCSockClientDlg* pDlg=(CCSockClientDlg*)pApp- m_pMainWnd;pDlg- m_MSGS.InsertString(0,m_

44、szBuffer);memset(m_szBuffer,0,sizeof(m_szBuffer);CAsyncSocket:OnReceive(nErrorCode);void MySock:OnSend(int nErrorCode) Send(m_szBuffer,m_nLength,0);m_nLength=0;memset(m_szBuffer,0,sizeof(m_szBuffer);/继续提请一个“读”的网络事件,接收Server消息AsyncSelect(FD_READ);CAsyncSocket:OnSend(nErrorCode);void MySock:OnConnect(

45、int nErrorCode) if (nErrorCode=0) m_bConnected=TRUE; CCSockClientApp* pApp=(CCSockClientApp*)AfxGetApp(); CCSockClientDlg* pDlg=(CCSockClientDlg*)pApp- m_pMainWnd; memcpy(m_szBuffer,Connected to ,13); strncat(m_szBuffer,pDlg- m_szServerAdr, sizeof(pDlg- m_szServerAdr); pDlg- m_MSGS.InsertString(0,m_

46、szBuffer); AsyncSelect(FD_READ); /提请一个“读”的网络事件,准备接收CAsyncSocket:OnConnect(nErrorCode);7 新建对话框IDD_Addr,用来输入IP地址和Port;生成新类CAddrDlg。增加两个Edit控件:IDC_Addr、IDC_Port按下表在ClassWizard中为CAddrDlg类添加变量。 Control IDTypeMemberIDC_AddrCStringm_AddrIDC_Portintm_Port8 在CSockClientDlg.ccp中添加代码 #include AddrDlg.hprotecte

47、d:int TryCount;MySock m_clientSocket;UINT m_szPort;public:char m_szServerAdr256;9 双击IDD_CSOCKCLIENT_DIALOG对话框中的“连接”按钮,添加以下代码 void CCSockClientDlg:OnConnect() m_clientSocket.ShutDown(2);m_clientSocket.m_hSocket=INVALID_SOCKET;m_clientSocket.m_bConnected=FALSE;CAddrDlg m_Dlg;/默认端口1088m_Dlg.m_Port=1088

48、;if (m_Dlg.DoModal()=IDOK & !m_Dlg.m_Addr.IsEmpty() memcpy(m_szServerAdr,m_Dlg.m_Addr,sizeof(m_szServerAdr); m_szPort=m_Dlg.m_Port; /建立计时器,每1秒尝试连接一次,直到连上或TryCount10SetTimer(1,1000,NULL); TryCount=0;10 添加Windows消息WM_TIMER响应函数OnTimer void CCSockClientDlg:OnTimer(UINT nIDEvent) if (m_clientSocket.m_hSo

49、cket=INVALID_SOCKET) BOOL bFlag=m_clientSocket.Create(0,SOCK_STREAM,FD_CONNECT); if(!bFlag) AfxMessageBox(Socket Error!); m_clientSocket.Close(); PostQuitMessage(0); return; m_clientSocket.Connect(m_szServerAdr,m_szPort);TryCount+;if (TryCount =10 | m_clientSocket.m_bConnected) KillTimer(1); if (Try

50、Count =10) AfxMessageBox(Connect Failed!); return;CDialog:OnTimer(nIDEvent);11 双击IDD_CSOCKCLIENT_DIALOG对话框中的“发送”按钮,添加以下代码 void CCSockClientDlg:OnSend() if (m_clientSocket.m_bConnected)m_clientSocket.m_nLength=m_MSG.GetWindowText(m_clientSocket.m_szBuffer, sizeof(m_clientSocket.m_szBuffer); m_clientS

51、ocket.AsyncSelect(FD_WRITE); m_MSG.SetWindowText();12 双击IDD_CSOCKCLIENT_DIALOG对话框中的“关闭”按钮,添加以下代码 void CCSockClientDlg:OnExit() /关闭Socketm_clientSocket.ShutDown(2);/关闭对话框EndDialog(0);12运行此项目,连接时输入主机名或IP均可,CAsyncSocket类会自动处理。二 服务端Server端的编程与Client端的类似,下面主要介绍他的Listen及Accept函数1 建立一个CNewSocket类,重载CAsyncS

52、ocket类的OnReceive、OnSend函数,如何进行信息的显示和发送可以参考Client程序。本例中采用将收到信息原封不动发回的方法来实现Echo功能,代码如下CNewSocket:OnReceive(int nErrorCOde)m_nLength=Receive(m_szBuffer,sizeof(m_szBuffer),0);/ 直接转发消息AsyncSelect(FD_WRITE);CNewSocket:OnSend(int nErrorCode)Send(m_szBuffer,m_nLength,0);2 建立一个CMyServerSocket类,重载CAsyncSocket

53、类的OnAccept函数代码如下在MyServerSocket.h中声明变量public::CNewSocket* m_pSocket;void CMyServerSocket:OnAccept(int nErrorCode)/侦听到连接请求,调用Accept函数CNewSocket* pSocket = new CNewSocket();if (Accept(*pSocket) pSocket- AsyncSelect(FD_READ);m_pSocket=pSocket;else delete pSocket;3 为对话框添加一个“侦听”按钮,添加如下代码在CsockServerDlg.h

54、中声明变量public:CMyServerSocket m_srvrSocket;void CCSockServerDlg:OnListen()if (m_srvrSocket.m_hSocket=INVALID_SOCKET) BOOL bFlag=m_srvrSocket.Create (UserPort,SOCK_STREAM,FD_ACCEPT); if (!bFlag) AfxMessageBox(“Socket Error!”); M_srvrSocket.Close(); PostQuitMessage(0); Return; /“侦听”成功,等待连接请求if (!m_srvrS

55、ocket。Listen(1) int nErrorCode = m_srvrSocket.GetLastError(); if (nError!=WSAEWOULDBLOCK) AfxMessageBox(“Socket Error!”); M_srvrSocket.Close(); PostQuitMessage(0); Return; 4 目前程序只能实现Echo功能,将信息原封不动的转发,若能将Accept中由CNewSocket* pSocket = new CNewSocket();得到的Socket指针存入一个CList或一个数组中,便像Client端那样,对所有的连接进行读写控

56、制。三 总结CAsyncSocket类为我们使用Socket提供了极大方便。建立Socket的WSAStartup过程和bind过程被简化成为Create过程,IP地址类型转换、主机名和IP地址转换的过程中许多复杂的变量类型都被简化成字符串和整数操作,特别是CAsyncSocket类的异步特点,完全可以替代繁琐的线程操作。MFC提供了大量的类库,我们若能灵活的使用他们,便会大大提高编程的效率。四 一个基于UDP的网络通迅程序整个例子有两个程序组成,一个发送数据,另一个程序接收数据后,完成绘图工作。本文程序运行效果图如下: 一、发送程序首先建立数据发送程序(Fason)。一共发送四个数据:圆心的

57、X坐标、圆心的Y坐标、圆半径R、圆的颜色。它的实现主要如下: void CFasonDlg:OnSend() UpdateData(TRUE);CString m_Getstring;this-m_Cob.GetLBText(m_Cob.GetCurSel(),m_Getstring);if(m_Getstring=_T(Red)yuan1.color=1;if(m_Getstring=_T(Green)yuan1.color=2;if(m_Getstring=_T(Blue)yuan1.color=3;yuan1.x=m_x;yuan1.y=m_y;yuan1.r=m_r;p=&yuan1;

58、CSocket m_hSocket;m_hSocket.Create(2330,SOCK_DGRAM);m_hSocket.SendTo( p,sizeof(yuan1),3550,127.0.0.1);/用结构体发送。 m_x=0; m_y=0; m_r=0; m_hSocket.Close(); UpdateData(FALSE);发送数据时有一个技巧,就是所有数据放在一个结构体中来发送,不用一个一个发送。但是不能在结构体中包含CString等可以变长的数据类型。二、接收程序 下面我们看一下接收数据端的程序(Jieshou)。如下: void CDASocket:OnReceive(int

59、 nErrorCode) char buff256;int ret=0;ret=Receive(buff,256);if(ret=ERROR)TRACE(ERROR!);else m_pDoc-Presscessding(buff);CAsyncSocket:OnReceive(nErrorCode);三、数据处理与显示我们设计程序时,数据通常在文档中处理,显示工作在视图中完成。当整个程序较小时,这感觉不到有何好处,但整个程序较大时,程序的条理就会较清晰,易读性好。所以一定要时时养成良好的设计习惯。数据在文档中处理如下:void CJieshouDoc:Presscessding(char*

60、lbuff)buff=(struct yuan*)lbuff;p.x=buff-x;p.y=buff-y;p.r=buff-r;p.color=buff-color;UpdateAllViews(NULL);在视图中的显示如下: void CJieshouView:OnDraw(CDC* pDC)CJieshouDoc* pDoc = GetDocument();ASSERT_VALID(pDoc);x=pDoc-p.x;y=pDoc-p.y;r=pDoc-p.r;if(pDoc-p.color=1)pDC-SelectObject(new CBrush(RGB(255,0,0);if(pDoc-p.color=2)pDC-SelectObject(new CBrush(RGB(0,255,0);if(pDoc-p.color=3)pDC-SelectObject(ne

展开阅读全文
温馨提示:
1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
2: 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
3.本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
关于我们 - 网站声明 - 网站地图 - 资源地图 - 友情链接 - 网站客服 - 联系我们

copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!